Noether.Either (noether v0.2.5)
This module hosts several utility functions to work with {:ok, _} | {:error, _}
values.
These type of values will be then called Either
.
Link to this section Summary
Functions
Given an {:ok, value}
and a function that returns an Either value, it applies the function on the value
. It effectively "squashes" an {:ok, {:ok, v}}
or {:ok, {:error, _}}
to its most appropriate representation.
If an {:error, _}
is given, it is returned as-is.
Please be careful and only use bind with functions that return either {:ok, } or {:error, }, otherwise you will break the Associativity law.
Given a list of Either, the function is mapped only on the elements of type {:ok, _}
. Other values will be discarded. A list of the results is returned outside of the tuple.
Given a value and two functions that return an Either, it applies the first one and returns the result if it matches {:ok, _}
. Otherwise the second function is applied.
Given an Either and two functions, it applies the first or second one on the second value of the tuple, depending if the value is {:ok, _}
or {:error, _}
respectively.
It returns true
only if the value given matches a {:error, value}
type.
Alias for bind/2
Alias for join/1
.
Given an {:ok, {:ok, value}}
it flattens the ok unwrapping the value
and returning {:ok, value}
.
If an {:error, _}
is given, it is returned as-is.
Given an {:ok, value}
and a function, it applies the function on the value
returning {:ok, f.(value)}
.
If an {:error, _}
is given, it is returned as-is.
Given a list of values and a function returning {:ok, any}
or {:error, any}
, it applies the function on every
value
returning {:ok, values}
if every f.(v)
results in {:ok, v}
; returning {:error, _}
if f.(v) results in an
.
Given an Either and one function, it applies the function to the {:error, _}
tuple.
It returns true
only if the value given matches a {:ok, value}
type.
Given an Either and a function, it returns the value as-is when it's ok, or executes the function and returns its result.
Given a value
and a function, it applies the function on the value
returning {:ok, f.(value)}
.
If the function throws an exception e
then it is wrapped into an {:error, e}
.
It returns the value of an {:ok, value}
only if such a tuple is given. If not, the default value (nil
if not provided) is returned.
Given any value, it makes sure the result is an Either type.
Given any value, it makes sure the result is an Either type.
Link to this section Types
either()
fun0()
@type fun0() :: (-> any())
fun1()
Link to this section Functions
bind(a, f)
Given an {:ok, value}
and a function that returns an Either value, it applies the function on the value
. It effectively "squashes" an {:ok, {:ok, v}}
or {:ok, {:error, _}}
to its most appropriate representation.
If an {:error, _}
is given, it is returned as-is.
Please be careful and only use bind with functions that return either {:ok, } or {:error, }, otherwise you will break the Associativity law.
examples
Examples
iex> bind({:ok, 1}, fn a -> {:ok, a + 1} end)
{:ok, 2}
iex> bind({:ok, 1}, fn _ -> {:error, 5} end)
{:error, 5}
iex> bind({:error, 1}, fn _ -> {:ok, 45} end)
{:error, 1}
cat_either(a, f)
Given a list of Either, the function is mapped only on the elements of type {:ok, _}
. Other values will be discarded. A list of the results is returned outside of the tuple.
examples
Examples
iex> cat_either([{:ok, 1}], &(&1 + 1))
[2]
iex> cat_either([{:ok, 1}, {:error, 2}, {:ok, 3}], &(&1 + 1))
[2, 4]
choose(a, f, g)
Given a value and two functions that return an Either, it applies the first one and returns the result if it matches {:ok, _}
. Otherwise the second function is applied.
examples
Examples
iex> choose(0, fn a -> {:ok, a + 1} end, fn b -> {:ok, b + 2} end)
{:ok, 1}
iex> choose(0, fn _ -> {:error, 1} end, fn b -> {:ok, b + 2} end)
{:ok, 2}
iex> choose(0, fn _ -> {:error, 1} end, fn _ -> {:error, 2} end)
{:error, 2}
either(a, f, g)
Given an Either and two functions, it applies the first or second one on the second value of the tuple, depending if the value is {:ok, _}
or {:error, _}
respectively.
examples
Examples
iex> either({:ok, 1}, &(&1 + 1), &(&1 + 2))
{:ok, 2}
iex> either({:error, 1}, &(&1 + 1), &(&1 + 2))
{:error, 3}
error?(a)
It returns true
only if the value given matches a {:error, value}
type.
examples
Examples
iex> error?({:ok, 1})
false
iex> error?({:error, 2})
true
iex> error?(3)
false
flat_map(either, f)
Alias for bind/2
examples
Examples
iex> flat_map({:ok, 1}, fn a -> {:ok, a + 1} end)
{:ok, 2}
iex> flat_map({:ok, 1}, fn _ -> {:error, 5} end)
{:error, 5}
iex> flat_map({:error, 1}, fn _ -> {:ok, 45} end)
{:error, 1}
flatten(either)
Alias for join/1
.
examples
Examples
iex> flatten({:ok, {:ok, 1}})
{:ok, 1}
iex> flatten({:ok, 1})
** (FunctionClauseError) no function clause matching in Noether.Either.join/1
iex> flatten({:error, "Value not found"})
{:error, "Value not found"}
join(a)
Given an {:ok, {:ok, value}}
it flattens the ok unwrapping the value
and returning {:ok, value}
.
If an {:error, _}
is given, it is returned as-is.
examples
Examples
iex> join({:ok, {:ok, 1}})
{:ok, 1}
iex> join({:ok, 1})
** (FunctionClauseError) no function clause matching in Noether.Either.join/1
iex> join({:error, "Value not found"})
{:error, "Value not found"}
map(a, f)
Given an {:ok, value}
and a function, it applies the function on the value
returning {:ok, f.(value)}
.
If an {:error, _}
is given, it is returned as-is.
examples
Examples
iex> map({:ok, -1}, &Kernel.abs/1)
{:ok, 1}
iex> map({:error, "Value not found"}, &Kernel.abs/1)
{:error, "Value not found"}
map_all(values, f)
Given a list of values and a function returning {:ok, any}
or {:error, any}
, it applies the function on every
value
returning {:ok, values}
if every f.(v)
results in {:ok, v}
; returning {:error, _}
if f.(v) results in an
.
examples
Examples
iex> map_all(["23:50:07.0123456", "23:50:07.123Z"], &Time.from_iso8601/1)
{:ok, [~T[23:50:07.012345], ~T[23:50:07.123]]}
iex> map_all(["23:50:61", "23:50:07.123Z"], &Time.from_iso8601/1)
{:error, :invalid_time}
map_error(a, f)
Given an Either and one function, it applies the function to the {:error, _}
tuple.
examples
Examples
iex> map_error({:ok, 1}, &(&1 + 1))
{:ok, 1}
iex> map_error({:error, 1}, &(&1 + 1))
{:error, 2}
ok?(a)
It returns true
only if the value given matches a {:ok, value}
type.
examples
Examples
iex> ok?({:ok, 1})
true
iex> ok?({:error, 2})
false
iex> ok?(3)
false
or_else(a, f)
Given an Either and a function, it returns the value as-is when it's ok, or executes the function and returns its result.
examples
Examples
iex> or_else({:ok, 1}, fn _ -> {:ok, 2} end)
{:ok, 1}
iex> or_else({:error, 1}, fn _ -> {:ok, 2} end)
{:ok, 2}
iex> or_else({:error, 1}, fn x -> {:ok, x + 2} end)
{:ok, 3}
try(value, f)
Given a value
and a function, it applies the function on the value
returning {:ok, f.(value)}
.
If the function throws an exception e
then it is wrapped into an {:error, e}
.
examples
Examples
iex> try("42", &String.to_integer/1)
{:ok, 42}
iex> try("nan", &String.to_integer/1)
{:error, %ArgumentError{message: "errors were found at the given arguments:\n\n * 1st argument: not a textual representation of an integer\n"}}
unwrap(a, b \\ nil)
It returns the value of an {:ok, value}
only if such a tuple is given. If not, the default value (nil
if not provided) is returned.
examples
Examples
iex> unwrap({:ok, 1})
1
iex> unwrap(2)
nil
iex> unwrap({:ok, 1}, :default_value)
1
iex> unwrap(2, :default_value)
:default_value
wrap(a)
Given any value, it makes sure the result is an Either type.
examples
Examples
iex> wrap({:ok, 1})
{:ok, 1}
iex> wrap({:error, 2})
{:error, 2}
iex> wrap(3)
{:ok, 3}
wrap_err(a)
Given any value, it makes sure the result is an Either type.
examples
Examples
iex> wrap_err({:ok, 1})
{:ok, 1}
iex> wrap_err({:error, 2})
{:error, 2}
iex> wrap_err(3)
{:error, 3}