[Haskell-cafe] Teaching Monads
Ronald Guida
oddron at gmail.com
Sat Jun 7 00:05:48 EDT 2008
Monads in Haskell are a topic that I, like most beginners, find
difficult and "mind-twisting". Now that I think I understand monads,
they seem to be very simple; I've read that this is a common
experience.
So I wonder, what would it take to help beginners catch on with a
minimum of fuss or frustration? The plethora of monad tutorials out
there is clear evidence that plenty of others have wondered the same
thing.
What made monads "click" for me is when I understood the following
things:
1. When monads are being used, closures are almost always involved.
2. These closures naturally arise when desugaring do-syntax.
do x1 <- m1 m1 >>= (\x1 ->
x2 <- m2 m2 >>= (\x2 -> [Eq1]
x3 <- m3 m3 >>= (\x3 ->
return (f x1 x2 x3) return (f x1 x2 x3))))
3. These closures are extremely similar to the closures that arise
when desugaring let-syntax.
let x1 = f1 in f1 -$ (\x1 -> Where:
let x2 = f2 in f2 -$ (\x2 -> (-$) :: a -> (a -> b) -> b
let x3 = f3 in f3 -$ (\x3 -> x -$ f = f x
f x1 x2 x3 f x1 x2 x3)))
4. While I can think of a monad as a fancy container that holds an
element of type "t", it might be more accurate to think of a monad
as a container that merely displays the type "t" as a label for its
contents. The container might hold one object of type "t", or it
might hold several. It might not be holding any at all. Perhaps
the container /never/ holds an object of type "t", but instead it
holds a set of instructions to produce such an object.
(e.g. Reader, State).
Naturally, it's hard to illustrate nested closures, higher-order
functions, and objects that aren't really there. It's easy to
illustrate a sequential scheme where a single "thing" passes through a
series of operations, while some related data travels in parallel.
m1 >>= f1 >>= f2 >>= f3 [Eq2]
In any case, the extreme similarity between desugared "do" and
desugared "let" leads me to think of the concepts of a manual
plumbing system and a monadic plumbing system.
Basically, a manual plumbing system is what I have if I'm threading
information down through a series of nested function calls in a
certain stereotypical way. A monadic plumbing system is what I get
when I introduce the appropriate monad to encapsulate my threading.
In fact, if I look at Wadler [*], there are three examples of an
evaluator that use what I'm calling "manual plumbing". In section
2.5, the operations required of a monad (return, bind) pretty much
just drop right out. Wadler even points out the similarity between
"bind" and "let".
Now that I finally "get it", I feel that the Wadler paper, section 2.5
in particular, is probably a better introduction than many of the
monad tutorials out there. Moreover, I feel that for /some/ of
the tutorials out there, they spend too much time and too many
illustrations explaining things like [Eq2], and then they quickly
present do-notation and gloss over [Eq1].
For me, I found that that the concepts of "manual plumbing" and
"monadic plumbing" were key to actually grasping the Wadler paper and
understanding what monads are. In particular, I feel that these two
concepts might be a way to help other beginners catch on as well.
OK, so before I attempt to write a monad tutorial based on "manual
plumbing" and "monadic plumbing", I would like to know, does anyone
else think this is a good idea?
[*] "Monads for Functional Programming".
(http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf)
More information about the Haskell-Cafe
mailing list