Created
January 14, 2013 22:24
Revisions
-
reiddraper created this gist
Jan 14, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,304 @@ !SLIDE ## Monads in Erlang 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?]