ResultEx v0.1.0 ResultEx View Source

ResultEx is a module for handling functions returning a ResultEx.t/0. This module is inspired by the f# Result module, and Railway Oriented Programming as explained by Scott Wlaschin.

A result can be either the tuple {:ok, term} where term will be the expected return value of a function, or the tuple {:error, term} where term will be an explanation of what went wrong while executing a function.

Using this module, it will be possible to combine functions that return a ResultEx.t/0, and functions that take the value contained by the ok variant. In the case one of the functions returns an error variant, subsequent functions expecting an ok result can be prevented from being executed. Also, functions can be connected that will only execute in the case of an error.

Examples

iex> defmodule ResultExExample do
...>
...>   def divide(0, _), do: {:error, :zero_division_exception}
...>   def divide(0.0, _), do: {:error, :zero_division_exception}
...>   def divide(x, y), do: ResultEx.return(x / y)
...>   def subtract(x, y), do: ResultEx.return(x - y)
...>
...> end
...>
...> ResultExExample.divide(4, 2)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
{:ok, 0.0}
iex> ResultExExample.divide(4, 2)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
...> |> ResultEx.bind(fn x -> ResultExExample.divide(x, 2) end)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
{:error, :zero_division_exception}
iex> ResultExExample.divide(0, 2)
...> |> ResultEx.or_else(2)
2
iex> ResultExExample.divide(0, 2)
...> |> ResultEx.or_else_with(fn _err -> {:ok, 0} end)
{:ok, 0}

Link to this section Summary

Functions

Executes or partially executes the function given as value of the first ResultEx.t/0, and applies it with the value of the second ResultEx.t/0. If the function has an arity greater than 1, the returned ResultEx.t/0 value will be the function partially applied. (The function name is ‘appl’ rather than ‘apply’ to prevent import conflicts with ‘Kernel.apply’)

Partially applies ResultEx.bind/2 with the passed function

Applies a function with the value of the ResultEx.t/0. The passed function is expected to return a ResultEx.t/0. This can be useful for chaining functions together that elevate values into ResultEx.t/0s

Unwraps the ResultEx.t/0 to return its value. The second argument will be a specific error message to throw when the ResultEx.t/0 is an Error

Flatten nested ResultEx.t/0s into a single ResultEx.t/0

Flattens an Enum.t/0 of ResultEx.t/0s into a ResultEx.t/0 of enumerables

Partially applies ResultEx.map/2 with the passed function

Runs a function against the ResultEx.t/0s value. If the ResultEx.t/0 is an error, the function will not be executed

Unwraps the ResultEx.t/0 to return its value. If the ResultEx.t/0 is an error, it will return the default value passed as second argument instead

Unwraps the ResultEx.t/0 to return its value. If the ResultEx.t/0 is an error, the given function will be applied with the unwrapped error instead

Elevates a value to a ResultEx.t/0 type

Converts the ResultEx.t/0 to an Option. An Option is a {:some, term} tuple pair, or the :none atom

Unwraps the ResultEx.t/0 to return its value. Throws an error if the ResultEx.t/0 is an error

Link to this section Types

Link to this type t() View Source
t() :: {:ok, term()} | {:error, term()}

Link to this section Functions

Link to this function appl(error, error) View Source
appl(t(), t()) :: t()

Executes or partially executes the function given as value of the first ResultEx.t/0, and applies it with the value of the second ResultEx.t/0. If the function has an arity greater than 1, the returned ResultEx.t/0 value will be the function partially applied. (The function name is ‘appl’ rather than ‘apply’ to prevent import conflicts with ‘Kernel.apply’)

Examples

iex> value_result = {:ok, 1}
...> function_result = {:ok, fn value -> value + 1 end}
...> ResultEx.appl(function_result, value_result)
{:ok, 2}

iex> {:ok, fn value1, value2, value3 -> value1 + value2 + value3 end}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 2})
...> |> ResultEx.appl({:ok, 3})
{:ok, 6}

iex> {:error, "no such function"}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
{:error, "no such function"}

iex> {:ok, fn value1, value2, value3 -> value1 + value2 + value3 end}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:error, "no such value"})
{:error, "no such value"}
Link to this function bind(fun) View Source
bind((term() -> t())) :: (t() -> t())

Partially applies ResultEx.bind/2 with the passed function.

Link to this function bind(result, fun) View Source
bind(t(), (term() -> t())) :: t()

Applies a function with the value of the ResultEx.t/0. The passed function is expected to return a ResultEx.t/0. This can be useful for chaining functions together that elevate values into ResultEx.t/0s.

Examples

iex> divide = fn
...>   0 -> {:error, "Zero division"}
...>   n -> {:ok, n / 2}
...> end
...> divide.(4)
...> |> ResultEx.bind(divide)
{:ok, 1.0}

iex> divide = fn
...>   0 -> {:error, "Zero division"}
...>   n -> {:ok, n / 2}
...> end
...> divide.(0)
...> |> ResultEx.bind(divide)
{:error, "Zero division"}
Link to this function expect!(arg1, message) View Source
expect!(t(), String.t()) :: term()

Unwraps the ResultEx.t/0 to return its value. The second argument will be a specific error message to throw when the ResultEx.t/0 is an Error.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.expect!("The value was not what was expected")
5
Link to this function flatten(result) View Source
flatten(t()) :: t()

Flatten nested ResultEx.t/0s into a single ResultEx.t/0.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.return()
...> |> ResultEx.return()
...> |> ResultEx.flatten()
{:ok, 5}

iex> {:ok, {:ok, {:error, "Oops"}}}
...> |> ResultEx.flatten()
{:error, "Oops"}
Link to this function flatten_enum(enum) View Source
flatten_enum(Enum.t()) :: t()

Flattens an Enum.t/0 of ResultEx.t/0s into a ResultEx.t/0 of enumerables.

Examples

iex> [{:ok, 1}, {:ok, 2}, {:ok, 3}]
...> |> ResultEx.flatten_enum()
{:ok, [1, 2, 3]}

iex> [{:ok, 1}, {:error, "Oops"}, {:ok, 3}]
...> |> ResultEx.flatten_enum()
{:error, "Oops"}

iex> %{a: {:ok, 1}, b: {:ok, 2}, c: {:ok, 3}}
...> |> ResultEx.flatten_enum()
{:ok, %{a: 1, b: 2, c: 3}}

iex> %{a: {:ok, 1}, b: {:error, "Oops"}, c: {:ok, 3}}
...> |> ResultEx.flatten_enum()
{:error, "Oops"}
Link to this function map(fun) View Source
map((term() -> term())) :: (t() -> t())

Partially applies ResultEx.map/2 with the passed function.

Link to this function map(result, fun) View Source
map(t(), (term() -> term())) :: t()

Runs a function against the ResultEx.t/0s value. If the ResultEx.t/0 is an error, the function will not be executed.

Examples

iex> result = {:ok, 1}
...> ResultEx.map(result, &(&1 + 1))
{:ok, 2}

iex> result = {:error, "Oops"}
...> ResultEx.map(result, &(&1 + 1))
{:error, "Oops"}
Link to this function or_else(arg1, default) View Source
or_else(t(), term()) :: term()

Unwraps the ResultEx.t/0 to return its value. If the ResultEx.t/0 is an error, it will return the default value passed as second argument instead.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.or_else(4)
5

iex> {:error, "Oops"}
...> |> ResultEx.or_else(4)
4
Link to this function or_else_with(arg, fun) View Source
or_else_with(t(), (term() -> term())) :: term()

Unwraps the ResultEx.t/0 to return its value. If the ResultEx.t/0 is an error, the given function will be applied with the unwrapped error instead.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.or_else_with(fn err -> IO.inspect(err) end)
5

iex> {:error, "Oops"}
...> |> ResultEx.or_else_with(fn err -> err <> "!" end)
"Oops!"
Link to this function return(value) View Source
return(term()) :: t()

Elevates a value to a ResultEx.t/0 type.

Examples

iex> ResultEx.return(1)
{:ok, 1}
Link to this function to_option(arg) View Source
to_option(t()) :: {:some, term()} | :none

Converts the ResultEx.t/0 to an Option. An Option is a {:some, term} tuple pair, or the :none atom.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.to_option()
{:some, 5}

iex> {:error, "Oops"}
...> |> ResultEx.to_option()
:none
Link to this function unwrap!(arg) View Source
unwrap!(t()) :: term()

Unwraps the ResultEx.t/0 to return its value. Throws an error if the ResultEx.t/0 is an error.

Examples

iex> ResultEx.return(5)
...> |> ResultEx.unwrap!()
5