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 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

@type either() :: {:ok, any()} | {:error, any()}
@type fun0() :: (-> any())
@type fun1() :: (any() -> any())

Link to this section Functions

@spec bind(either(), fun1()) :: either()

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}
Link to this function

cat_either(a, f)

@spec cat_either([either()], fun1()) :: [any()]

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]
Link to this function

choose(a, f, g)

@spec choose(any(), fun1(), fun1()) :: either()

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}
Link to this function

either(a, f, g)

@spec either(either(), fun1(), fun1()) :: either()

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}
@spec error?(any()) :: boolean()

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
Link to this function

flat_map(either, f)

@spec flat_map(either(), fun1()) :: either()

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}
Link to this function

flatten(either)

@spec flatten(either()) :: 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"}
@spec join(either()) :: either()

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"}
@spec map(either(), fun1()) :: either()

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"}
Link to this function

map_all(values, f)

@spec map_all([any()], (any() -> either())) :: {:ok, [any()]} | {:error, any()}

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}
Link to this function

map_error(a, f)

@spec map_error(either(), fun1()) :: either()

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}
@spec ok?(any()) :: boolean()

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
@spec or_else(either(), fun1()) :: either()

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}
@spec try(any(), fun1()) :: either()

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"}}
Link to this function

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
@spec wrap(any()) :: either()

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}
@spec wrap_err(any()) :: either()

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}