Current section
Files
Jump to
Current section
Files
lib/control/continuation.ex
defmodule Control.Continuation do
@moduledoc """
This module provides the Continuation Monad, in which every other monad can be implemented.
```elixir
defmodule Maybe do
@moduledoc false
@nothing :nothing
@just :just
use ContinuationMonad
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
use ContinuationMonad
end
end
defp _return(x) do
{@just, x}
end
defp _bind(@nothing, _a2mb) do
@nothing
end
defp _bind({@just, a}, a2mb) do
a2mb.(a)
end
def return(x) do
ic(_return(x))
end
def nothing() do
ic(@nothing)
end
# Wrapping / Unwrapping
defp ic(ma) do
make_ic(&_bind/2).(ma)
end
def run(m) do
make_run(&_return/1).(m)
end
end
defmodule MaybeClient do
use Maybe
def some_fun() do
monad do
x <- return("eggs")
y <- return("bacon")
return({x, y})
end
end
run(some_fun())
end
```
"""
@cont :cont
# Monad implementation
defp return(a) do
{@cont, fn fun -> fun.(a) end}
end
@doc """
This is the classic monadic *bind* function. In Haskell this would be
```
Monad a >>= \a -> Monad b
```
"""
def {@cont, inC} ~>> a2cb do
cont(fn out -> inC.(fn a -> run_cont(a2cb.(a), out) end) end)
end
@doc """
Shortcut for ~>>
"""
def ca >>> cb do
ca ~>> fn _ -> cb end
end
# Monad implementation, helpers
defp cont(fun) do
{@cont, fun}
end
defp run_cont({@cont, inC}, fun) do
inC.(fun)
end
@doc """
allows for early exits.
"""
def call_cc(fun) do
cont(fn out -> run_cont(fun.(fn a -> cont(const(out.(a))) end), out) end)
end
# Applicative implementation
@doc """
Any Monad instance is also an instance of Applicative. This function is equivalent to *return*
"""
def pure(a) do
return(a)
end
@doc """
applies a function from a -> b that is within the Monad to a Monad of type a and produces a Monad of type b.
"""
def apa2b <~> apa do
apa2b ~>> fn a2b -> apa ~>> fn a -> pure(a2b.(a)) end end
end
# Functor implementation
@doc """
Applies a function of type a -> b to a Functor of type a. Produces a Functor of type b.
"""
def fmap(a2b, fa) do
pure(a2b) <~> fa
end
# helper functions
@doc """
Take a value x and produces a function that ignores its input and produces x.
"""
def const(x) do
fn _ -> x end
end
@doc """
Identity function
"""
def id(x) do
x
end
# injections
@doc """
This functions produces a "lift" function, that lifts the monad instances into the continuation monad.
"""
def make_ic(bind) do
fn m -> cont(fn fred -> bind.(m, fred) end) end
end
@doc """
Produces a function that "executes" the continuation monad.
"""
def make_run(return) do
fn m -> run_cont(m, return) end
end
end