# Haskell/Understanding monads

Monads are very useful in Haskell, but the concept is usually difficult for newcomers to grasp. Since they have so many applications, people often explain them from a particular point of view, which can confuse your understanding of monads in their full glory.

Historically, monads were introduced into Haskell to perform input/output. After all, lazy evaluation means that the order of evaluation is rather unpredictable, whereas a predetermined execution order is crucial for things like reading and writing files. Hence, a method for specifying a *sequence of operations* was needed, and monads were exactly the right abstraction for that.

But monads are by no means limited to input/output; they can model any imperative language. The choice of monad determines the semantics of this language, i.e., whether it supports exceptions, state, non-determinism, continuations, coroutines and so on^{[1]}.

The present chapter introduces the basic notions with the example of the `Maybe`

monad, the simplest monad for handling exceptions. Beginning Haskell programmers will probably also want to understand the `IO`

monad and then broaden their scope to the many other monads and the effects they represent; this chapter provides the corresponding pointers.

## Definition[edit]

Let us dive in with both feet. A *monad* is defined by three things:

- a type constructor
`M`

; - a function
`return`

^{[2]}; and - an operator
`(>>=)`

which is pronounced "bind".

The function and operator are methods of the `Monad`

type class, have types

return :: a -> M a (>>=) :: M a -> ( a -> M b ) -> M b

and are required to obey three laws that will be explained later on.

For a concrete example, take the `Maybe`

monad. The type constructor is `M = Maybe`

so that `return`

and `(>>=)`

have types

return :: a -> Maybe a (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b

They are implemented as

return x = Just x (>>=) m g = case m of Nothing -> Nothing Just x -> g x

and our task is to explain how and why this definition is useful.

### Motivation: Maybe[edit]

To see the usefulness of `(>>=)`

and the `Maybe`

monad, consider the following example: imagine a family database that provides two functions

father :: Person -> Maybe Person mother :: Person -> Maybe Person

that look up the name of someone's father or mother, returning `Nothing`

if they are not stored in the database. With them, we can query various grandparents. For instance, the following function looks up the maternal grandfather:

maternalGrandfather :: Person -> Maybe Person maternalGrandfather p = case mother p of Nothing -> Nothing Just m -> father m -- mother's father

Or consider a function that checks whether both grandfathers are in the database:

bothGrandfathers :: Person -> Maybe (Person, Person) bothGrandfathers p = case father p of Nothing -> Nothing Just f -> case father f of Nothing -> Nothing Just gf -> -- found first grandfather case mother p of Nothing -> Nothing Just m -> case father m of Nothing -> Nothing Just gm -> -- found second one Just (gf, gm)

What a mouthful! Every single query might fail by returning `Nothing`

and the whole function must fail with `Nothing`

if that happens.

Clearly there has to be a better way to write that than repeating the case of `Nothing`

again and again! Indeed, and that's what the `Maybe`

monad is set out to do. For instance, the function retrieving the maternal grandfather has exactly the same structure as the `(>>=)`

operator, and we can rewrite it as

maternalGrandfather p = mother p >>= father

With the help of lambda expressions and `return`

, we can rewrite the mouthful of two grandfathers as well:

bothGrandfathers p = father p >>= (\f -> father f >>= (\gf -> mother p >>= (\m -> father m >>= (\gm -> return (gf,gm) ))))

While these nested lambda expressions may look confusing to you, the thing to take away here is that `(>>=)`

eliminates any mention of `Nothing`

, shifting the focus back to the interesting part of the code.

### Type class[edit]

In Haskell, the type class `Monad`

is used to implement monads. It is provided by the Control.Monad module and included in the Prelude. The class has the following methods:

class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b fail :: String -> m a

Aside from return and bind, it defines two additional functions `(>>)`

and `fail`

.

The operator `(>>)`

called "then" is a mere convenience and commonly implemented as

m >> n = m >>= \_ -> n

It is used for sequencing two monadic actions when the second does not care about the result of the first, which is common for monads like `IO`

.

printSomethingTwice :: String -> IO () printSomethingTwice str = putStrLn str >> putStrLn str

The function `fail`

handles pattern match failures in `do`

notation. It's an unfortunate technical necessity and doesn't really have anything to do with monads. You are advised to not call `fail`

directly in your code.

## Notions of Computation[edit]

While you probably agree now that `(>>=)`

and `return`

are very handy for removing boilerplate code that crops up when using `Maybe`

, there is still the question of why this works and what this is all about.

To answer this, we shall write the example with the two grandfathers in a very suggestive style:

bothGrandfathers p = do f <- father p -- assign p's father to f gf <- father f -- assign f's father (p's paternal grandfather) to gf m <- mother p -- assign p's mother to m gm <- father m -- assign m's father (p's maternal grandfather) to gm return (gf, gm) -- return result pair

If this looks like a code snippet of an imperative programming language to you, that's because it is. In particular, this imperative language supports *exceptions* : `father`

and `mother`

are functions that might fail to produce results, i.e. raise an exception, and when that happens, the whole `do`

-block will fail, i.e. terminate with an exception.

In other words, the expression `father p`

, which has type `Maybe Person`

, is interpreted as a statement of an imperative language that returns a `Person`

as result. This is true for all monads: a value of type `M a`

is interpreted as a statement of an imperative language that returns a value of type `a`

as result; and the semantics of this language are determined by the monad `M`

.

Now, the bind operator `(>>=)`

is simply a function version of the semicolon. Just like a `let`

expression can be written as a function application,

let x = foo in bar corresponds to (\x -> bar) foo

an assignment and semicolon can be written as the bind operator:

x <- foo; bar corresponds to foo >>= (\x -> bar)

The `return`

function lifts a value `a`

to a full-fledged statement `M a`

of the imperative language.

Different semantics of the imperative language correspond to different monads. The following table shows the classic selection that every Haskell programmer should know. If the idea behind monads is still unclear to you, studying each of the examples in the following subchapters will not only give you a well-rounded toolbox but also help you understand the common abstraction behind them.

Semantics | Monad | Wikibook chapter |
---|---|---|

Exception (anonymous) | `Maybe` |
Haskell/Understanding monads/Maybe |

Exception (with error description) | `Error` |
Haskell/Understanding monads/Error |

Global state | `State` |
Haskell/Understanding monads/State |

Input/Output | `IO` |
Haskell/Understanding monads/IO |

Nondeterminism | `[]` (lists) |
Haskell/Understanding monads/List |

Environment | `Reader` |
Haskell/Understanding monads/Reader |

Logger | `Writer` |
Haskell/Understanding monads/Writer |

Furthermore, the semantics do not only occur in isolation but can also be mixed and matched. This gives rise to monad transformers.

Some monads, like monadic parser combinators have loosened their correspondence to an imperative language.

## Monad Laws[edit]

We can't just allow any junky implementation of `(>>=)`

and `return`

if we want to interpret them as the primitive building blocks of an imperative language. For that, an implementation has to obey the following three laws:

m >>= return = m -- right unit return x >>= f = f x -- left unit (m >>= f) >>= g = m >>= (\x -> f x >>= g) -- associativity

In Haskell, every instance of the `Monad`

type class is expected to obey them.

### Return as neutral element[edit]

The behavior of `return`

is specified by the left and right unit laws. They state that `return`

doesn't perform any computation, it just collects values. For instance,

maternalGrandfather p = do m <- mother p gm <- father m return gm

is exactly the same as

maternalGrandfather p = do m <- mother p father m

by virtue of the right unit law.

### Associativity of bind[edit]

The law of associativity makes sure that – just like the semicolon – the bind operator `(>>=)`

only cares about the order of computations, not about their nesting; e.g. we could have written `bothGrandfathers`

like this (compare with our earliest version without `do`

):

bothGrandfathers p = (father p >>= father) >>= (\gf -> (mother p >>= father) >>= (\gm -> return (gf,gm) ))

The associativity of the *then* operator `(>>)`

is a special case:

(m >> n) >> o = m >> (n >> o)

It is easier to picture the associativity of bind by recasting the law as

(f >=> g) >=> h = f >=> (g >=> h)

where `(>=>)`

is the monad composition operator, a close analogue of the (flipped) function composition operator `(.)`

, defined as

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c f >=> g = \x -> f x >>= g

## Monads and Category Theory[edit]

Monads originally come from a branch of mathematics called Category Theory. Fortunately, it is entirely unnecessary to understand category theory in order to understand and use monads in Haskell. However, the definition of monads in Category Theory uses a slightly different presentation. Translated into Haskell, this presentation gives an alternative yet equivalent definition of a monad which can give us some additional insight ^{[3]}.

So far, we have defined monads in terms of `>>=`

and `return`

. The alternative definition, instead, starts with monads as functors with two additional combinators:

fmap :: (a -> b) -> M a -> M b -- functor return :: a -> M a join :: M (M a) -> M a

(Reminder: as discussed in the chapter on the functor class, a functor `M`

can be thought of as container, so that `M a`

"contains" values of type `a`

, with a corresponding mapping function, i.e. `fmap`

, that allows functions to be applied to values inside it.)

Under this interpretation, the functions behave as follows:

`fmap`

applies a given function to every element in a container`return`

packages an element into a container,`join`

takes a container of containers and flattens it into a single container.

With these functions, the bind combinator can be defined as follows:

m >>= g = join (fmap g m)

Likewise, we could give a definition of `fmap`

and `join`

in terms of `(>>=)`

and `return`

:

fmap f x = x >>= (return . f) join x = x >>= id

### Is my Monad a Functor?[edit]

At this point we might, with good reason, deduce that all monads are by definition functors as well. While according to category theory that is indeed the case, GHC does it differently, and the `Monad`

and `Functor`

classes are unrelated. That will likely change in future versions of Haskell, so that every `Monad`

instance will be guaranteed to have a matching `Functor`

instance and the corresponding `fmap`

. Meanwhile, `Control.Monad`

defines `liftM`

, a function with a strangely familiar type signature...

liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r

As you might suspect, `liftM`

is merely `fmap`

implemented with `(>>=)`

and `return`

, just as we have done above. For a properly implemented monad with a matching `Functor`

(that is, pretty much any *sensible* monad) `liftM`

and `fmap`

are interchangeable.

## Notes[edit]

- ↑ Indeed, thanks to the versatility of monads, in Haskell none of these constructs is a built-in part of the language; rather, they are defined by the standard libraries!
- ↑ This
`return`

function has nothing to do with the`return`

keyword found in imperative languages like C or Java; don't conflate these two. - ↑ Deep into the Advanced Track, we will cover the theoretical side of the story in the chapter on Category Theory.