Monads for the Working Haskell Programmer
-- a short tutorial.

Theodore Norvell
Memorial University of Newfoundland

New: Updated to Haskell '98.

This short tutorial introduces monads to Haskell programmers. It applies to Haskell
'98. Gofer programmers (are there any left?) can read it too; there is a section at the
end detailing the differences between Haskell and Gofer around monads and another about
the differences between Haskell 1.3, Haskell 1.4, and Haskell 98.

The reader is assumed to have a familiarity with the basics of Haskell programming such
as data declarations, function definitions, and lambda expressions. Familiarity with
classes and instance declarations will help.

Simulating states without Monads

where a, b, c, and d all have the same type, State.
In a sense this definition is very similar to an imperative program in which a
represents the initial state, d represents the final state, and b and c
represent intermediate states. The functions f1 w, g1 w, h1 w x,
and i1 w x y can be thought of as imperative routines that transform the state
and produce results. The results are like the return values in C programs and are bound to
variables x, y, and z in the example. A C routine that
corresponds to this would look something like this:

All this explicit passing of states around can get a bit tedious, especially when
programs are modified. It also makes the program hard to read vs. the equivalent C
program.

Note that if we ignore the w, x, y, and z, then g1,
h1, and i1 are being composed. Can we define a kind of "composition
operator" that allows us to deal with the returned values as well as the state?

Simulating states with Monads

The functions that transform the state in the example above all have the type State
-> (State, a) for some result type a. Let's generalize over the type of
the state and create a type to represent these transforms

type StateTrans s a = s -> (s, a)

Let us define two functions. The first is a kind of composition function.

You should verify that f is equal to f1, if g = g1, h =
h1, and i = i1.

(Warning, if you really try to make the above definitions of >>= and return,
your Haskell compiler will complain, for reasons that will be explained later. However,
you could try changing the names a little, e.g. change >>= to >==
and change return to rtn.)

A nicer syntax

Now Haskell provides a nice syntax to sugar-coat the calls to >>=. It
turns out that the definition of f can also be written as

f w = do x <- g w
y <- h w x
z <- i w x y
return z

The "do" is a keyword of Haskell. Any program involving a "do" can
be translated to one that doesn't use "do" by the following 4 rules:

1 An expression

do

pattern<-expression

morelines

becomes expression>>= (\pattern -> domorelines)

2 An expression

do

expression

morelines

becomes expression>> domorelines

3 An expression

do

let declarationList

morelines

becomes

let

declarationList

in

do morelines

4. Finally when there is only one line in the do, an expression

do

expression

becomes expression

In the second rule, we saw the >> operator; this is used when the result of the
first operand is not subsequently used. It can always be defined as

p >> q = p >>= (\ _ -> q)

So

do p
q

is the same as

do _ <- p
q

The "do" notation follows the same conventions as other multi-line constructs
in Haskell. All lines must be vertically alligned. Alternatively, you may use braces and
semicolons if you prefer "free format":

do {x <- g w ; y <- h w x ;
z <- i w x y ; return z }

How to Really Declare the StateTrans Monad.

So far we've seen the monad concept applied to implicitly passing state. However monads
can be used to implement several other programming features including: consuming input,
producing output, exceptions and exception handling, nondeterminisim. To handle this
variety, the basic operations of >>= and return are overloaded
functions.

(Haskell requires that overloaded functions be declared in class declarations and
defined in instance declarations. This is the reason that >>= and return
can not be defined exactly as described in previous sections.)

The class that >>= and return are declared in is
called Monad and is itself declared in the Haskell Prelude. That declaration looks
like this

To make a state transform monad that actually works with Haskell's "do"
notation, we have to declare >>= and return within an instance
declaration. There is one minor problem; type synonyms can not be used in instance
declarations, so we define StateTrans s a as a new type.

We don't need to define the >> operator; it is defined automatically in
terms of >>=.

Note these new definitions change the type of functions like our example function
f. Indeed f is no longer equal to f1, since its type is different. To apply
members of the monad, we define a new function

applyST :: StateTrans s a -> s -> (s, a)
applyST (ST p) s = p s

Now applyST f is equal to f1.

Which is the Monad?

Technically each Monad (in Haskell) is not a type, but a "type contructor".
In our state transformer example, we have actually declared an infinite set of monads. For
each type s, there is a type constructor StateTrans s.
Each such type constructor has been declared to be a Monad by the instance declaration
above.

An example

A short example shows how the StateTrans monad lets you code in a fairly imperative
style.

We will implement a variation on Euclid's algorithm for finding the greatest common
divisor of two positive integers.

while x != y do
if x < y
then y := y-x
else x := x-y
return x

First we must define a type to represent the state:

type ImpState = (Int, Int)

Next we define some simple state transformers to access and change the state. We use
the type () and its sole value, (), when a state transformer does not
return a useful value.

And finally a function to construct an initial state, run the program and discard the
final state

greatestCommonDivisor x y = snd( applyST gcdST (x,y) )

This small example only hints at the utility of monads. It would be much shorter to
write the algorithm in a conventional functional style. The savings from not having to
explicitly pass the state around become larger as the program becomes larger.

Monads, Monoids, and Identities

The term "monad" comes from category theory, which is a branch of algebra
(or, depending on whom you talk to, algebra is a branch of category theory). There is no
need to understand the algebra at all to understand the use of monads in functional
programming. This section and the next, just touch on the algebra a little bit.

Monads share some similarity with monoids* , with >>=
being similar to the monoid operation and the return operator taking the place of
the identity member. Specifically we have the following identities

We define mzero and mplus to make StateTransEx s
a member of class MonadPlus. mzero will mean throw an exception. mplus
will give a means to recover from an exception; mplus p q will mean, execute p,
but if an exception is thrown in p, then recover by executing q instead.

Since MonadPlus is not in the Prelude, but rather the Monad library, we
must import it from the Monad library (the import declaration must go at the top of your
Haskell module).

Now, if we execute p `mplus` q, and p fails, then the computation
will be resumed with q. Note that q starts with the state that pstarted with, not the state that p had reached when the exception
ocurred; p and q can be regarded as alternative computations. Although
I've called this exception handling, "backtracking" is arguably a more accurate
term.

We can use mplus and mzero to implement backtracking algorithms.
Consider the classic problem of finding a way to place 8 queens on an 8 by 8 chess board
such that no queen attacks another.

First the state

type QState = ([Int], [Int], [Int])

We use three lists to keep track of three sets: the set of occupied columns, the set of
occupied south-west diagonals and the set of occupied south-east diagonals. The south-west
diagonals are represented by the difference in the column and row number. The south-east
diagonals are represented by the sum of the row and column number. There are functions to
get and set each of these components of the state:

The next routine attempts to place a queen at a particular spot, failing if the new
queen would attack one that is already on the board.
(I'm assuming there is no other queen in the same row, so no check is
required to see if the row is occupied.)

place r c =
do tryPutCol c
tryPutSWDiag (c-r)
tryPutSEDiag (c+r)

The main algorithm to place queens in each of rows [0..r-1] of a board with colNum
columns is:

(We could also define tryEach in terms of the library function, msum,
which takes a list of monad members and combines them with mplus: tryEach xs
f = msum (map f xs) ).

To find an arrangement on an 8 by 8 chess board we write:

applySTE (queens 8 8) ([], [], [])

Nondeterminism

The StateTransEx monad provides a limited form of nondeterminism. Computations either
succeed or fail, but if they succeed, they succeed but once. For example in

do (p `mplus` q)
r

if p succeeds and then r then fails, q will not be given a
chance to "execute".

To get nondeterminism of the sort found in languages such as Icon, SNOBOL, and Prolog,
we need to allow a computation to succeed more than once. To create such a monad, we
replace the Maybe type constructor with the list type constructor:

The type is

newtype StateTransMany s a = STM( s -> [(s, a)] )

I leave it as an exercise to define >>=, return, mplus,
and mzero for this monad, and to change the queens example to generate all
solutions to the 8-queens problem.

The IO Monad

Haskell defines a monad called IO that is used to describe computations that interact
with the operating system -- in particular to perform input and output. For example, here
is how you can write a function to read a file, printing an error message if the file can
not be read

You can see that the IO monad also supports exception handling, though with the
"catch" function, not the mplus operator. (mplus would be
inappropriate because changes to the world can not be undone!)

In Haskell the main program should be of type IO().

It is often said that pure functional languages can't be used to write interactive
programs. At first glance the IO monad seems to contradict this idea. You can think
of it this way: When your functional program is executed, it does not interact with the
operating system, it merely computes an object of type IO(), which describes a
set of possible interactive computations. An interpreter interacts with the environment to
make one of these computations happen. The fact that Haskell is a lazy language is key to
this, for the set of computations for many applications is infinite, even if each
computation is finite. The choice of which computation is needed is governed by the input;
thanks to lazyness, only the computation that is actually required is computed.

Lists as a Monad

(The notation [ ] in the first line of each instance declaration refers to the
list type constructor, i.e. the function that maps each type to its corresponding list
type.)

The definition of the list constructor as a monad allows one to write such things as

do a <- [1,2,3]
b <- [3,4,5]
return (a+b)

This evaluates to

[4,5,6,5,6,7,6,7,8] ,

just as does the list comprehension

[ a+b | a <- [1,2,3],
b <- [3,4,5] ]

Monads and Software Engineering

The key to engineering a large software project is to make changes easy..

Monads can be used to make functional programs far more adaptable. You need to
insert another processing step? Go right ahead, don't worry about plumbing the state. You
need another variable in the state? No problem, just change the underlying state and the
basic members of the monad. You need to output messages from your computation? No problem,
just change the monad to add an output string. You need to handle exceptions or
nondeterminism? No problem, just change the monad.

It might be said that Haskell with monads does not give you much that you won't find in
an imperative, nondeterministic language, with extensible, strong, but generic typing, and
a powerful applicative expression sublanguage. The problem is there is no such language in
common use. Monads make up for many of the drawbacks of Haskell relative to imperative
languages, but without giving up any of its strengths.

More information

Monads can be used for parsing. By using the remaining input as state, the StateTrans
monad can be used to write deterministic recursive-descent parsers. Better yet, the
StateTransEx and StateTransMany parsers can (respectively) be used to create backtracking
parsers and non-deterministic parsers (allowing ambiguous grammars). Monadic parsing
is the topic of the following paper:

I like to add an output for error and warning message, to the monad, and the
possibility of fatal errors that can not be recovered from. I also use a clearer
separation between parsing and lexical analysis than Hutton and Meijer. My own monadic
parsing combinators are available on the web at http://www.engr.mun.ca/~theo/Misc/index.html#ParsingMonad

The IO monad and the theory behind it is reported in

Philip Wadler, How to declare an imperative, ACM Computing Surveys,
29(3):240--263, September 1997.

There is a whole lot that could be said about the mathematical theory of
monads. It is my belief that most programmers don't need to know much of this theory to
reap the benefits of programming with monads. Philip Wadler's papers give an introduction
to the mathematics and pointers back to the earlier, more mathematical, literature.

A Note for Gofer Programmers

Almost everything in this tutorial applies equally to Gofer. However a few notations
are different. I think the following table completely summarizes the notational
differences assuming you are using Gofer 2.30 and the cc.prelude prelude.

Haskell

Gofer

>>=

replace by

`bind`

>>

no equivalent?

return

replace by

result

newtype

replace by

data

MonadPlus

replace by

Monad0 and MonadPlus

Gofer supports both the "do" syntax (if Gofer is compiled with the right
options) and a "comprehension" syntax for monads explained next. In Gofer
the so-called "list" comprehension notation is an alternative to the
"do" notation, no matter whether you are using the list monad or any other
monad. You can write

[a+b | a<-getX, b<-getY]

which means the same as

do a <- getX
b <- getY
return (a+b)

The advantage of the "do" notation is that it doesn't force you to end with a
"return".

In Gofer, each instance of class Monad must be an instance of class Functor. To be in
class Functor a monad m must support a function called map of type (a -> b) -> (m a
-> m b). The map function lifts an ordinary function to a monad function. For monads,
it can always be defined by

map f p = [f a | a <- p]

In Gofer, use of the IO monad requires a special compilation option and inclusion of
the file iomonad.gs.

A Note for Haskell 1.3 and 1.4 users

In Haskell 1.3 and 1.4 mzero is called zero and mplus
is called ++. There is a separate class MonadZero, declaring the zero. All the
classes are declared in the Prelude, so you do not need to import from Monad.

End Notes

A monoid is an algebraic structure consisting of a set S and an operation *
with the following properties

Closure:

x*y is in S, if x and y are both in S.

Associativity:

x*(y*z) = (x*y)*z for all x, y, and z in S.

Identity:

There is an element e in S such that e*x= x*e = x , for all x
in S .

Examples of monoids are the integers with multiplication as the operator, character
strings with catenation as the operator, functions with composition as the operator, and
programming langauge statements with sequential composition as the operator. Also any
group is a monoid and any monoid that has inverses is a group.