Elixir With Expressions
A with expression runs a chain of pattern matches in order. When every match succeeds, it returns the value built from the matched parts.
Two ok steps build one greeting
Each step matches an ok tuple and binds the value inside it. Both steps succeed, so the do block runs.
name_step = {:ok, "Ana"}
age_step = {:ok, 31}
result =
with {:ok, name} <- name_step,
{:ok, age} <- age_step do
"#{name} is #{age}"
end
IO.puts(result)A failed step passes straight out
The second step holds an error tuple, so it does not match its ok pattern. The with returns that tuple unchanged, and inspect shows it.
name_step = {:ok, "Ana"}
age_step = {:error, "age missing"}
result =
with {:ok, name} <- name_step,
{:ok, age} <- age_step do
"#{name} is #{age}"
end
IO.inspect(result)The do block combines all the matched values
The do block can compute with every bound value. Here it multiplies the price by the count.
price_step = {:ok, 200}
count_step = {:ok, 3}
shipping_step = {:ok, 40}
total =
with {:ok, price} <- price_step,
{:ok, count} <- count_step,
{:ok, shipping} <- shipping_step do
price * count + shipping
end
IO.puts(total)Example
name_step = {:ok, "Ana"}
score_step = {:error, "score missing"}
profile =
with {:ok, name} <- name_step,
{:ok, score} <- score_step do
"#{name} scored #{score}"
end
message =
case profile do
{:error, reason} -> "lookup failed: #{reason}"
text -> text
end
IO.puts(message)Key points
- Arrow step: each step in a with uses <- to match a value against a pattern.
- Chain order: steps run top to bottom, and later steps can use values bound by earlier steps.
- Success result: when every step matches, the do block builds the final value.
- Straight exit: when a step does not match, with returns that step's value unchanged.
- Result tuples: with often chains {:ok, value} tuples, so one failed step returns its error tuple.
In this example, the first step binds name, and the second step fails because its tuple is an error tuple. The with returns that tuple, and the case turns it into a friendly message.
Note
with replaces a deep nest of case expressions when several ok tuples must all succeed.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does with {:ok, a} <- {:ok, 6}, {:ok, b} <- {:error, "stop"} do a + b end return?