Skip to content

Instantly share code, notes, and snippets.

@kana-sama
Last active September 4, 2020 05:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kana-sama/23516580ba59d8e83a898c1c28b8e55a to your computer and use it in GitHub Desktop.
Save kana-sama/23516580ba59d8e83a898c1c28b8e55a to your computer and use it in GitHub Desktop.
Result/Either monad in Elixir
defmodule Result do
@type result :: any
@type reason :: any
@type ok :: {:ok, result}
@type error :: {:error, reason}
@type t :: ok | error
@spec ok(result) :: ok
def ok(result) do
{:ok, result}
end
@spec fail(reason) :: error
def fail(reason) do
{:error, reason}
end
@spec and_then(t, (result -> t)) :: t
def and_then({:error, _reason} = m, _callback), do: m
def and_then({:ok, result}, callback) do
callback.(result)
end
@spec and_then(t, (result -> result)) :: t
def map({:error, _reason} = m, _updater), do: m
def map({:ok, result}, updater) do
ok updater.(result)
end
@spec and_then(t, (reason -> reason)) :: t
def map_error({:ok, _result} = m, _updater), do: m
def map_error({:error, reason} = m, updater) do
fail updater.(reason)
end
end
defmodule TestModule do
def fetch do
Result.ok 9.0
end
def div_ten_by_x(x) do
case x do
0.0 ->
Result.fail "zero"
_ ->
{:ok, 10 / x} # tuples are ok too
end
end
end
TestModule.fetch
|> IO.inspect # {:ok, 9.0}
|> Result.map(&(&1 + 1))
|> IO.inspect # {:ok, 10.0}
|> Result.and_then(&TestModule.div_ten_by_x/1)
|> IO.inspect # {:ok, 1.0}
|> Result.map(&(&1 - 1))
|> IO.inspect # {:ok, 0.0}
|> Result.and_then(&TestModule.div_ten_by_x/1)
|> IO.inspect # {:error, "zero"}
|> Result.map(&(&1 + 1))
|> IO.inspect # {:error, "zero"}
|> Result.and_then(&TestModule.div_ten_by_x/1)
|> IO.inspect # {:error, "zero"}
|> Result.map_error(&String.capitalize/1)
|> IO.inspect # {:error, "Zero"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment