Skip to content

Alternative pipe operators for clean handling of `{:ok, value}` and `{:error, reason}` tuples in Elixir

License

Notifications You must be signed in to change notification settings

jmargenberg/monok

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monok

Build Status Coverage Status Hex.pm

Monad on :ok

Provides the infix pipe operators ~>, ~>>, and <~> for writing clean pipelines that treat {:ok, result} and {:error, reason} tuples like functors, monads or applicatives.

Also provides the functions fmap, bind and lift as which are functionally identical but are less cryptic and can be used without overriding any inifix operators which could potentially conflict with other libraries.

Why would you ever do this?

Whilst writing unnecessary macros and overriding infix operators are both generally considered bad practice I thought I'd try this out given just how freqently {:ok, result} and {:error, reason} tuples are encountered in Elixir.

Functor Pipelines

Allows you to write clean pipelines that transforms values inside of {:ok, value} tuples.

iex> {:ok, [1, 2, 3]}
...> ~> Enum.sum()
...> ~> div(2)
{:ok, 3}

If the input is an {:error, reason} tuple it is carried through the pipeline without applying any transformations.

iex> {:error, :reason}
...> ~> Enum.sum()
...> ~> div(2)
{:error, :reason}

Monad Pipelines

Allows you to write clean pipelines that transform values in {:ok, value} tuples with functions that also return {:ok, value} tuples.

iex> decrement = fn
...>   x when x > 0 -> {:ok, x - 1}
...>   _ -> {:error, :input_too_small}
...>  end
iex> {:ok, 3}
...> ~>> decrement.()
...> ~>> decrement.()
{:ok, 1}

If at any point in the pipeline an {:error, reason} tuple is returned it is carried through without any of the transformation functions being applied.

iex> decrement = fn
...>   x when x > 0 -> {:ok, x - 1}
...>   _ -> {:error, :input_too_small}
...>  end
iex>
...> {:ok, 3}
...> ~>> (fn _ -> {:error, :contrived_example} end).()
...> ~>> decrement.()
...> ~>> decrement.()
{:error, :contrived_example}

Mixed Pipelines

These pipe operators don't have to be used in seperate pipelines but can be used together or even with the |> standard pipe operator.

iex> 7
...> |> (&(if &1 > 5, do: {:ok, &1}, else: {:error, :too_low})).()
...> ~> Integer.to_string()
...> ~>> (&(if &1 |> String.length() > 0, do: {:ok, &1 <> "!"}, else: {:error, :empty_string})).()
{:ok, "7!"}

About

Alternative pipe operators for clean handling of `{:ok, value}` and `{:error, reason}` tuples in Elixir

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages