Current section
Files
Jump to
Current section
Files
lib/right.ex
defmodule Right do
@moduledoc """
A `Right` contains any value that is not a nil.
"""
@enforce_keys [:value]
defstruct [:value]
defdelegate new(value), to: Either
@doc """
Applies the given function to the value contained inside the `Right`. Returns a
new `Right` with the result of that calculation inside it.
"""
def map(%Right{value: value}, func) when is_function(value) do
value
|> compose(func)
|> Either.new()
end
def map(right = %Right{}, %Right{value: value}) do
map(right, value)
end
def map(%Right{value: value}, func) do
func = curry(func)
value
|> func.()
|> Either.new()
end
@doc """
Returns the result of the right hand function (the 3rd argument) applied to the value
contained inside the `Right`. This defaults to the identity function, as a fold is
where we usually want to 'unwarap' the value.
"""
def fold(%Right{value: value}, _left_function, right_function \\ fn(x) -> x end) do
right_function.(value)
end
defp compose(f, g) when is_function(g) do
fn arg -> compose(f, g.(arg)) end
fn arg -> compose(curry(f), curry(g).(arg)) end
end
defp compose(f, arg) do
f.(arg)
end
defp curry(fun) do
{_, arity} = :erlang.fun_info(fun, :arity)
curry(fun, arity, [])
end
defp curry(fun, 0, arguments) do
apply(fun, Enum.reverse arguments)
end
defp curry(fun, arity, arguments) do
fn arg -> curry(fun, arity - 1, [arg | arguments]) end
end
end