Skip to content

Instantly share code, notes, and snippets.

@cqfd
Created July 28, 2011 01:12
Show Gist options
  • Save cqfd/1110731 to your computer and use it in GitHub Desktop.
Save cqfd/1110731 to your computer and use it in GitHub Desktop.
Monads, explained with Ascii art.
Monads are composed of three ingredients.
First, for a given monad m, there are monadic values of type m a, for some type
variable a. In Haskell, if a variable x has type t, we write x :: t.
Here's a picture of a monadic value of type m a.
+--------\
| | \
| m | a > :: m a
| | /
+--------/
Picture it as a box, labelled by m, with a triangle on the side, labelled by a.
The second ingredient is a function, which maps an argument of type a to a new
monadic value of type m b, where b is another type variable. Sometimes b will be
equal to a, but it needn't be.
.\---------\
. \ | \
. a > m | b > :: a -> m b
. / | /
./---------/
The diagram shows that if you were to stick an a into the left-hand side of the
picture, you'd get a m b box. You can think of this second ingredient as being
a monadic callback; given an a, you can use it to produce an m b.
The third ingredient in a monad is a way to combine an m a boxe with an
a -> m b box, such that you get another monadic box. This third ingredient is
another function. It's type is m a -> (a -> m b) -> m b. If you give it an m a
and a function of type (a -> m b), it will give you an m b.
Here's what happens if you feed an m a into an (a -> m b):
+--------\---------\
| | \ | \
| m | a > m | b >
| | / | /
+--------/---------/
From far away, this looks like an m b:
+--------\
| | \
| m | b > :: m b
| | /
+--------/
Even if you know nothing else about monads, your inner computer scientist should
enjoy these diagrams. These little boxes are composable: you can take a little
m a box, combine it with an (a -> m b) box, and get another box, this time
with type m b. You could then combine this new box with a (b -> m c) box,
and get back an m c box. We're combining building blocks and getting bigger building
blocks back. Awesome.
This idea, of composing building blocks together to get new building blocks, is one
of the fundamental ideas of computer science, and it's what monads are all about.
** The monad laws
There are actually a few other ingredients to monads, called the monad laws. There
are three of them. They're easy and they fall right out of the pictures.
First, suppose you have a
.\---------\
. \ | \
. a > m | b > :: a -> m b
. / | /
./---------/
and you also have a
.\---------\
. \ | \
. b > m | c > :: b -> m c
. / | /
./---------/
You can combine these guys to get one of these
.\---------\---------\
. \ | \ | \
. a > m | b > m | c > :: a -> m c
. / | / | /
./---------/---------/
One of the monad laws says that if you combine three such callbacks, it
doesn't matter how you parenthesize the combining. You can combine the first two,
and then add on the third, or you can combine the last two
and then add the first one in front. The combining is associative. At the end
of the day, no matter how you parenthesize, you get the same callback:
.\---------\---------\---------\
. \ | \ | \ | \
. a > m | b > m | c > m | d > :: a -> m d
. / | / | / | /
./---------/---------/---------/
The next two monad laws state that for any monad m, there exists a funny
box that looks kind of like this:
.\--\
. \ \
. a > a >
. / /
./--/
That is, there exists a function of type (a -> m a) for any type a that is as
thin as possible. Combining it with a
.\---------\
. \ | \
. a > m | b >
. / | /
./---------/
on the left gives
.\\---------\
. \\ | \
. a >> m | b >
. // | /
.//---------/
One of the monad laws says that this equals
.\---------\
. \ | \
. a > m | b >
. / | /
./---------/
which is the thing we started with. Likewise if you add it on the right:
.\---------\\--\
. \ | \\ \
. a > m | b >> b >
. / | // /
./---------//--/
The final monad law says this is just what we started with:
.\---------\
. \ | \
. a > m | b >
. / | /
./---------/
** Takeaways
Whenever you want to understand a particular monad, you need to understand how
to combine monadic values of type m a
+--------\
| | \
| m | a > :: m a
| | /
+--------/
with a monadic callback,
.\---------\
. \ | \
. a > m | b >
. / | /
./---------/
to get a new monadic value of type m b,
+--------\---------\
| | \ | \
| m | a > m | b >
| | / | /
+--------/---------/
Each monad implements this means of combination in its own way, but the basic
idea is always the same.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment