!SLIDE
monads are simple
!SLIDE
a monad is a monoid in the category of endofunctors
!SLIDE
problem?
!SLIDE
monads get a bad wrap from monad tutorials
!SLIDE
a monad is a Burrito
!SLIDE
a computation container
!SLIDE
category theory
!SLIDE
i'll give a concrete definition, in Erlang
!SLIDE
@@@ erlang
-type monad() :: term().
!SLIDE
@@@ erlang
-type list(Something).
!SLIDE
@@@ erlang
-spec return(term()) -> monad().
!SLIDE
@@@ erlang
-spec bind(monad(), fun((term()) -> monad())) -> monad().
!SLIDE
@@@ erlang
-type either() :: {ok, term()} | {error, term()}.
!SLIDE
@@@ erlang
-spec return(term()) -> either().
return(Value) ->
{ok, Value}.
!SLIDE
@@@ erlang
-spec bind(monad(), fun((term()) -> either())) -> either().
bind({ok, Val}, MonadicFun) ->
MonadicFun(Val);
bind({error, _Reason}=Error, _MonadicFun) ->
Error.
!SLIDE
motivation
!SLIDE
@@@ erlang
doThatThing() ->
case partOne() of
{ok, Result1} ->
case partTwo(Result1) of
{ok, Result2} ->
{ok, 'wow_you_followed_this_far?'};
{error, _Reason2}=Reason2 ->
Reason2
end;
{error, _Reason1}=Reason1 ->
Reason1
end.
!SLIDE
what we really want to say
@@@ erlang
[fun partOne/0, fun partTwo/1].
!SLIDE
@@@ erlang
bind(partOne(), fun partTwo/1).
!SLIDE
we can chain this together
!SLIDE
@@@ erlang
pipe(Monad, Funs) ->
lists:foldl(flip(fun bind/2), Monad, Funs).
!SLIDE
@@@ erlang
mAddOne(Val) ->
Val + 1.
mAlwaysError(Val) ->
{error, Val}.
!SLIDE
@@@ erlang
pipe({ok, 0}, [fun mAddOne/1, fun mAddOne/1, mAddOne/1, fun mAlwaysError/1]).
!SLIDE
polymorphism
!SLIDE
fucking erlang
!SLIDE
modules
!SLIDE
@@@ erlang
ModuleVar:bind(...)
ModuleVar:return(...)
!SLIDE
other monads
!SLIDE
writer monad
!SLIDE
@@@ erlang
return(Val) ->
{Val, []}.
writer_bind({Val, SideVal}, MonadFun) ->
{NewVal, NewSideVal} = MonadFun(Val),
{NewVal, SideVal ++ NewSideVal}.
!SLIDE
questions?
A brief digression, function composition
!SLIDE
Result = g(f(X)).
NOTE: we can reason about this
!SLIDE
Composition is associative
(g ∘ f)(x) = g(f(x))
!SLIDE
Let's write comp
in Erlang
comp(A, B) ->
fun(Input) ->
A(B(Input))
end.
!SLIDE
Now let's use it,
(comp(fun addOne/1, fun multiplyTwo/1))(5) %% -> 11
!SLIDE
Functions aren't just abstractions, we've generalized them.
!SLIDE
Sometimes we have a domain-specific idea of how to compose data or computation. This is a monad.
!SLIDE
Return the first 'failure', otherwise keep going
!SLIDE
[fun thingOne/1,
fun thingTwo/1,
fun thingThree/1].
!SLIDE
But here's what we do
doThatThing() ->
case partOne() of
{ok, Result1} ->
case partTwo(Result1) of
{ok, Result2} ->
{ok, 'wow_you_followed_this_far?'};
{error, _Reason2}=Reason2 ->
Reason2
end;
{error, _Reason1}=Reason1 ->
Reason1
end.
!SLIDE
In programming, a concrete monad implements the monad 'interface'
bind
return
!SLIDE
bind
defines how your data or compuation
composes.
!SLIDE
return
takes a non-monadic value and places
it inside the monad
!SLIDE
For our failure monad, we might define
bind
like this:
!SLIDE
bind({ok, X}, NextFun) ->
NextFun(X);
bind({error, _Reason}=Reason, _NextFun) ->
Reason.
!SLIDE
return(Val) ->
{ok, Val}.
!SLIDE
There are actually two other monad functions, but they're not as important:
>>
fail
[Note: writer monad for timings?]
Is there a video of the talk anywhere?