One minute
Use Tuple-Wrapping for More Elegant ‘With’ Expressions
The error from the following code will be ambiguous (we do not know, whether the height or width is missing):
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height)
do
{:ok, width * height}
else
:error -> {:error, :wrong_data}
end
By wrapping our return values inside tuples, with distinct atoms as first values, we can pattern match on specific error values inside the else block:
with {:width, {:ok, width}} <- {:width, Map.fetch(opts, :width)},
{:height, {:ok, height}} <- {:height, Map.fetch(opts, :height)}
do
{:ok, width * height}
else
{:width, :error} -> {:error, :missing_width}
{:height, :error} -> {:error, :missing_height}
end
A more complicated example:
with {:user, {:ok, user}} <- {:user, Users.get(user_id)},
{:game, {:ok, game}} <- {:game, Games.get(game_id)},
{:full, false} <- {:full, Game.is_full?(game)},
{:started, false} <- {:started, Game.is_started?(game)},
{:allowed, true} <- {:allowed, User.has_permission?(user, game)}
do
Game.add_user(game, user)
else
{:user, :not_found} -> {:error, "User not found"}
{:game, :not_found} -> {:error, "Game not found"}
{:full, true} -> {:error, "Game is full"}
{:started, true} -> {:error, "Game has already started"}
{:allowed, false} -> {:error, "User is not allowed to join this game"}
end
Read other posts
comments powered by Disqus