tagged v0.4.1 Tagged.PipeWith View Source

Generates a function for selective execution, with pass-through of terms that does not match, much like the regular with ... <- ..., do: ... construct.

Examples

Given a module that defines a success() | failure() type:

defmodule PipeWith do
  use Tagged

  deftagged not_an_integer(term())
  deftagged not_a_number(term())

  @type reason() :: not_an_integer() | not_a_number()

  deftagged success(integer())
  deftagged failure(reason())

  @type result() :: success() | failure()

  def validate_input(x) when is_integer(x), do: success(x)
  def validate_input(x), do: failure(not_an_integer(x))

  def next_number(x), do: x + 1

  def try_recovery({_, x}) when is_number(x), do: success(floor(x))
  def try_recovery({_, x}), do: failure(not_a_number(x))
end

This is quite similar to the regular with ... <- ..., do: ..., else: ... for happy paths:

iex> require PipeWith
iex> import PipeWith
iex> with success(v) <- validate_input(1),
...>      do: next_number(v)
2
iex> validate_input(1)
...> |> with_success(&next_number/1)
2

When the path is not a happy path, it offers more fluent control over recovery from failures at any point in the pipe:

iex> require PipeWith
iex> import PipeWith
iex> with success(v) <- validate_input(0.7) do
...>   next_number(v)
...> else
...>   failure(e) -> with success(v) <- try_recovery(e),
...>                      do: next_number(v)
...> end
1
iex> validate_input(0.7)
...> |> with_failure(&try_recovery/1)
...> |> with_success(&next_number/1)
1

Link to this section Summary

Link to this section Functions

Link to this function

gen_pipe_with(module, name, arity, ex_tag)

View Source