MonEx.Result (MonEx v0.2.1)

Copy Markdown View Source

A Result represents the outcome of an operation that can fail:

  • ok(value) — success, carrying a value
  • error(reason) — failure, carrying a reason

The runtime representation is just an idiomatic Elixir tuple ({:ok, value} or {:error, reason}), so MonEx slots in on top of any function that already returns those.

Summary

Types

Result type. ok(res) and error(err) expand to {:ok, res} and {:error, err} respectively.

Functions

Walks a list of Results and returns the unwrapped error reasons, preserving order.

Walks a list of Results and returns the unwrapped success values, preserving order.

Constructor macro: error(err) expands to {:error, err}. Works in both expressions and patterns.

Returns the input as-is if it is ok(). If error(), returns the second argument — either a Result directly, or a 1-arity function receiving the error and returning a Result.

Returns true if the argument is error(), false if ok().

Returns true if the argument is ok(), false if error().

Constructor macro: ok(res) expands to {:ok, res}. Works in both expressions and patterns.

Splits a list of Results into a map with :ok and :error keys pointing at the unwrapped values. Both keys are always present, even when one bucket is empty.

Re-runs the body block while it returns error(_). The first ok(_) short-circuits and is returned; if every attempt fails, the last error(_) is returned.

Evaluates exp, normalising the outcome into a Result

Returns x if the argument is ok(x). Otherwise consults the second argument

Converts a Result into an Option: ok(val) becomes some(val), error(_) becomes none(). Useful when you only care whether a value is present and want to drop the error reason.

Types

t(res, err)

@type t(res, err) :: {:ok, res} | {:error, err}

Result type. ok(res) and error(err) expand to {:ok, res} and {:error, err} respectively.

Functions

collect_error(results)

@spec collect_error([t(res, err)]) :: [err] when res: any(), err: any()

Walks a list of Results and returns the unwrapped error reasons, preserving order.

Examples

iex> [ok(1), error("oops")] |> collect_error
["oops"]

collect_ok(results)

@spec collect_ok([t(res, any())]) :: [res] when res: any()

Walks a list of Results and returns the unwrapped success values, preserving order.

Examples

iex> [ok(1), error("oops")] |> collect_ok
[1]

error(err)

(macro)

Constructor macro: error(err) expands to {:error, err}. Works in both expressions and patterns.

fallback(arg, f)

@spec fallback(t(res, err), t(res, err) | (err -> t(res, err))) :: t(res, err)
when res: any(), err: any()

Returns the input as-is if it is ok(). If error(), returns the second argument — either a Result directly, or a 1-arity function receiving the error and returning a Result.

Examples

iex> ok(5) |> fallback(fn _ -> 1 end)
ok(5)

iex> error("WTF") |> fallback(fn m -> ok("#{m}LOL") end)
ok("WTFLOL")

iex> error("WTF") |> fallback(ok(5))
ok(5)

is_error(x)

@spec is_error(t(any(), any())) :: boolean()

Returns true if the argument is error(), false if ok().

Examples

iex> is_error(error("Error"))
true

iex> is_error(ok(5))
false

is_ok(arg)

@spec is_ok(t(any(), any())) :: boolean()

Returns true if the argument is ok(), false if error().

Examples

iex> is_ok(ok(5))
true

iex> is_ok(error("Error"))
false

ok(res)

(macro)

Constructor macro: ok(res) expands to {:ok, res}. Works in both expressions and patterns.

partition(results)

@spec partition([t(res, err)]) :: %{ok: [res], error: [err]}
when res: any(), err: any()

Splits a list of Results into a map with :ok and :error keys pointing at the unwrapped values. Both keys are always present, even when one bucket is empty.

Examples

iex> [ok(1), error("oops"), ok(2)] |> partition
%{ok: [1, 2], error: ["oops"]}

iex> [ok(1)] |> partition
%{ok: [1], error: []}

retry(opts \\ [], list)

(macro)

Re-runs the body block while it returns error(_). The first ok(_) short-circuits and is returned; if every attempt fails, the last error(_) is returned.

Options

  • :n — number of retries to attempt after the initial call (default: 5)
  • :delay — milliseconds to sleep between attempts (default: 0)

Example

result = retry n: 3, delay: 3000 do
  remote_service()
end

Calls remote_service() up to 4 times (1 initial + 3 retries) with a 3-second pause between attempts.

try_result(mode \\ :full, list)

(macro)

Evaluates exp, normalising the outcome into a Result:

  • a raised exception becomes error(...),
  • a Result (ok(_) or error(_)) returned by exp is passed through unchanged,
  • any other value x becomes ok(x).

Modes

  • :full (default) — error(...) carries the exception struct
  • :messageerror(...) carries the exception message string
  • :moduleerror(...) carries the exception module

Examples

iex> try_result do
...>   5 + 5
...> end
ok(10)

iex> try_result do
...>   raise ArithmeticError, message: "bad argument"
...> end
error(%ArithmeticError{message: "bad argument"})

iex> try_result :message do
...>   raise ArithmeticError, message: "bad argument"
...> end
error("bad argument")

iex> try_result :module do
...>   raise ArithmeticError, message: "bad argument"
...> end
error(ArithmeticError)

unwrap(result, fallback \\ nil)

@spec unwrap(t(res, err), res | (err -> res)) :: res when res: any(), err: any()

Returns x if the argument is ok(x). Otherwise consults the second argument:

  • a 1-arity function — called with the error term; its return is returned
  • any other non-nil value — returned as-is
  • nil (the default, when no fallback is supplied) — re-raises the error term

Examples

iex> unwrap(ok(5))
5

iex> unwrap(error(:uh_oh), fn _ -> 10 end)
10

iex> unwrap(error(:uh_oh), 10)
10

unwrap_option(arg)

@spec unwrap_option(t(res, any())) :: MonEx.Option.t(res) when res: any()

Converts a Result into an Option: ok(val) becomes some(val), error(_) becomes none(). Useful when you only care whether a value is present and want to drop the error reason.

Examples

iex> unwrap_option(ok(5))
{:some, 5} # same as some(5)

iex> unwrap_option(error(:uh_oh))
{:none} # same as none()