🎓 A1Learner
🔍
0 of 54 lessons completed

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?