My preferred approach for this is to have a generic validate
helper which converts boolean into :ok | {:error, reason}
:
def validate(true, _reason), do: :ok
def validate(false, reason), do: {:error, reason}
And now with can be expressed as:
with :ok <- validate(is_integer(foo), :not_an_integer),
:ok <- validate(...),
...,
do: ...
I briefly discussed this in this blog post.