ok v0.2.0 OK
The OK
module enables clean and expressive error handling in pipelines.
Many Elixir libraries follow the tagged tuple convention for functions that will not alway return a valid response.
In case of a success the value is returned in an :ok
tagged tuple.
If the function fails then a reason is returned in an :error
tagged tuple.
Calling code the matches on these two possible outcomes.
case my_func(args) do
{:ok, value} ->
do_more(value) # continue with subsequent processing
{:error, reason} ->
{:error, reason} # return early.
end
OK
allows this code to be replaced by a result pipeline.
my_func(args)
~>> do_more
OK
treates the combination of tagged tuples {:ok, value} | {:error, reason}
as a result monad.
The result monad is sometimes know as the try or either monad.
Summary
Functions
Takes a result tuple and a next function. If the result tuple is tagged as a success then its value will be passed to the next function. If the tag is failure then the next function is skipped
Creates a failed result tuple with the given reason
Wraps a value as a successful result tuple
Macros
Result pipe operator. (Result monad bind operator)
Functions
Takes a result tuple and a next function. If the result tuple is tagged as a success then its value will be passed to the next function. If the tag is failure then the next function is skipped.
Examples
iex> OK.bind({:ok, 2}, fn (x) -> {:ok, 2 * x} end)
{:ok, 4}
iex> OK.bind({:error, :some_reason}, fn (x) -> {:ok, 2 * x} end)
{:error, :some_reason}
Macros
Result pipe operator. (Result monad bind operator)
The result pipe takes the value out of an {:ok, value}
tuple and passes it as the first argument to the function call on the right.
Examples
iex> {:ok, 5} ~>> double()
{:ok, 10}
iex> {:error, :previous_bad} ~>> double()
{:error, :previous_bad}
# x is {:ok, 7} defined in `OKTest`.
iex> x ~>> double()
{:ok, 14}
The result pipe is most useful when executing a series of operations that may fail.
iex> {:ok, 6} ~>> safe_div(3) ~>> double
{:ok, 4.0}
iex> {:ok, 6} ~>> safe_div(0) ~>> double
{:error, :zero_division}
It can be used in several ways.
Pipe to a local call.
This example is the same as calling double(5)
iex> {:ok, 5} ~>> double
{:ok, 10}
Pipe to a remote call.
This example is the same as calling OKTest.double(3)
iex> {:ok, 5} ~>> OKTest.double()
{:ok, 10}
iex> {:ok, 5} ~>> __MODULE__.double()
{:ok, 10}
Pipe with extra arguments
This example is the same as calling OK.safe_div(3, 4)
iex> {:ok, 6} ~>> safe_div(2)
{:ok, 3.0}
iex> {:ok, 6} ~>> safe_div(0)
{:error, :zero_division}
Given an anonymous function the following syntax needs to be used.
iex> {:ok, 3} ~>> (fn (x) -> {:ok, x + 1} end).()
{:ok, 4}
# decrement returns an anonymous function.
# weird I know but was needed as a test case
iex> {:ok, 6} ~>> decrement.(2)
{:ok, 4}