with chains
| Chain happy paths | |
| Else reroutes | |
| Filter with <- | |
| Flat instead of nested |
Chain happy paths
The with expression chains steps that each return ok tuples.
When every step matches, the do block runs with all the pieces bound.
One straight chain below replaces deep nesting of one case inside another.
user = %{name: "Ada", age: 36}
with {:ok, name} <- Map.fetch(user, :name),
{:ok, age} <- Map.fetch(user, :age) do
{:ok, {name, age}}
end
Else reroutes
When a step fails to match, with skips the do block and jumps to else.
Each else arm names one failure shape and states its recovery value.
The missing age below reroutes the whole chain to the tagged error.
user = %{name: "Ada"}
with {:ok, name} <- Map.fetch(user, :name),
{:ok, age} <- Map.fetch(user, :age) do
{:ok, {name, age}}
else
:error -> {:error, :missing_field}
end
Filter with <-
A left arrow step with a plain value on the left acts as a filter.
When the right side fails the test, the whole with returns that value at once.
The chain below passes only positive counts and stops on zero or less.
m = %{count: 3}
with {:ok, n} <- Map.fetch(m, :count),
true <- n > 0 do
{:ok, n}
end
Flat instead of nested
Nested case blocks push code rightward with every new check added.
One with lists the same checks top to bottom at a single level.
Prefer with when every step must succeed before the final result.
user = %{name: "Ada", age: 36}
with {:ok, name} <- Map.fetch(user, :name),
{:ok, age} <- Map.fetch(user, :age) do
{name, age}
end
Next: Modules
Article author: Arthur Isaev