Skip to content

Instantly share code, notes, and snippets.

@keathley
Created January 7, 2016 20:57
Show Gist options
  • Save keathley/bd6b31391f7e05dd8e44 to your computer and use it in GitHub Desktop.
Save keathley/bd6b31391f7e05dd8e44 to your computer and use it in GitHub Desktop.
Monads and Maybes in elixir
defprotocol Functor do
def fmap(data, func)
end
defprotocol Applicative do
def pure(data)
def run(wrapped_func, data)
end
defprotocol Monad do
def bind(ma, func)
end
defmodule Maybe do
defstruct id: :nothing, value: nil
def just(value) do
%Maybe{id: :just, value: value}
end
def nothing(_value \\ nil) do
%Maybe{id: :nothing}
end
end
defimpl Monad, for: Maybe do
import Maybe
def bind(%Maybe{id: :nothing}, _func), do: nothing
def bind(%Maybe{id: :just, value: val}, func) do
func.(val)
end
end
defimpl Applicative, for: Maybe do
import Maybe
import Functor
def pure(f), do: just(f)
def run(%Maybe{id: :nothing}, _), do: nothing
def run(%Maybe{id: :just, value: f}, something) do
fmap(something, f)
end
end
defimpl Functor, for: Maybe do
import Maybe
def fmap(%Maybe{id: :just, value: value}, func) do
just func.(value)
end
def fmap(%Maybe{id: :nothing}, _f) do
nothing
end
end
defimpl String.Chars, for: Maybe do
def to_string(%Maybe{value: value}), do: "#{value}"
end
defmodule Possibly do
import Maybe
import Functor
import Applicative
import Integer
import Monad
def main do
just(20)
|> bind(&half/1) # => just 10
|> bind(&half/1) # => just 5
|> bind(&half/1) # => nothing
|> bind(&half/1) # => nothing
end
def half(x) do
if is_even(x) do
just(round(x/2))
else
nothing
end
end
end
Possibly.main # => nil
@progsmile
Copy link

Nice!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment