## Monads for dummies

February 28, 2014

Don’t mind the linkbait title—I know you’re not a dummy. And you’re totally smart enough to understand monads.

There is no shortage of monad tutorials. I’ve even written a couple myself. But these tutorials try to get you from zero to hero at lightning speed. This one will be different. I’m not going to explain categories, T-algebras, functors, or any of that abstract nonsense. I’m also not going to teach you how to use monads effectively, or even try to convince you why they are useful at all.

So what’s the point then? The point is to make you not afraid of the word “monad.” You know the term comes from math. But the way monads are used in functional programming is pretty far removed from their mathematical heritage. So let’s not even bother—your time is precious. This tutorial will be very practical. I just want you to get the big picture and not feel intimidated by them—and you can check out other resources (like my other articles) for the details.

Okay, let’s get started. Oh by the way, I’m not going to use Haskell in this article, which is probably what you think of when you hear about monads. How about something a little more familiar, like Python? Sounds good.

Monads tend to come up a lot in functional programming. I’ve written about functional programming before, but all you need to know for now is that it’s a paradigm in which mutable data is generally discouraged, or even forbidden. Computation generally happens by composing pure functions together. A pure function is one that does nothing but return the result of a computation. It doesn’t print anything, store anything, ask for user input, etc. It just manipulates the data you pass it and returns more data.

You may be more familiar with object-oriented programming. Let me translate monads into OOP-speak. A monad is a class. It has a couple of methods:

class Monad: def __init__(self, x): raise NotImplementedError def bind(self, f): raise NotImplementedError

`x`

can be anything. `f`

is a function that takes something of the same type as `x`

(presumably from the monad) and returns a new monad. Lastly, `bind`

also returns a new monad (often from the result of `f`

). Literally that’s it. Maybe you don’t know what it’s used for, but at least now you’ve seen the interface.Typically, a monad acts as some sort of container, and

`bind`

applies a function to what it contains. Let’s make a monad that stores a single element:class SimpleMonad(Monad): def __init__(self, x): self.x = x def bind(self, f): return f(self.x)

To make this a little more concrete, this is how you use it:

def double(x): return SimpleMonad(x * 2) def add1(x): return SimpleMonad(x + 1) foo = SimpleMonad(5).bind(double).bind(add1)

Okay, so you can chain functions together with

`bind`

. But why would we do that? Equivalently, we could have just written `add1(double(5))`

, which is much shorter.The main idea is that monads don’t have to just call the functions you pass to

`bind`

. They can change the rules. For example, here is a monad that allows you to chain operations without worrying about null pointer errors.class MaybeMonad(Monad): def __init__(self, x): self.x = x def bind(self, f): if self.x is None: return self else: return f(self.x)

If any intermediate computation in a sequence of operations results in

`None`

, the entire expression becomes `None`

and no further operations are performed (much like how `NaN`

works in floating-point arithmetic, if you’re familiar with that). If you spend more time with monads, you’ll find that you can also use them to implement exception handling, mutable state, concurrency, and a bunch of other things.Remember: functional programming is all about writing programs by composing functions together.

*The power of monads is that they allow you to change the rules for how functions are composed.*When I was learning about monads, the main things I was confused about were:

- It seems like using monads requires you to write a lot of code, e.g.,
`SimpleMonad(5).bind(double).bind(add1)`

instead of`add1(double(5))`

. Do people really go through all this trouble? - How do I get the value
*out*of the monad? Can I access it like`monad.x`

? - I hear that Haskell doesn’t let you write “impure” functions that have side effects, but I know for a fact that Haskell programs can print to the screen and write to files. What’s the deal? Do monads somehow resolve this?

Well, I know the answers now, so let me share the love:

- Haskell has a special syntax for monads and Python doesn’t—so that’s why they don’t look very nice in Python. It’s actually quite brilliant. Check it out if you have time. Using it feels very natural and it looks a lot like imperative code.
- Some monads provide a “getter” function that allows you to get the value back out. But a monad is not required to have one. For some monads, it doesn’t make sense to take a value out of it. A monad is not required to act like a container. See #3.
- You’re right—all functions in Haskell are pure. Haskell has a neat trick for doing I/O. You can think of a Haskell program as a pure computation that returns a tree-like data structure, and this tree represents another program that does impure things.Now, building this tree can be done in a purely functional way—as is required in Haskell. But when you “run” a Haskell program, two things happen: 1) your pure Haskell computation is executed, resulting in this tree-like data structure, 2) the tree-program from step 1 (which can print to the screen and write to files) is also executed.It just so happens that a certain monad, especially when combined with Haskell’s special monad syntax, makes it easy to build this tree. This monad is called
`IO`

in Haskell. The bind operation does not call the function you pass it, as it did in our monad examples above. Rather, it just stores it in the tree. The runtime will call it when interpreting the tree. That’s the high-level idea. In this post, I implement this idea in Python, which will probably make it a little more clear for you.Lastly, the`IO`

monad does not have a “getter” function. For example, if you have an`IO`

action that asks a user for a string of input, you cannot extract the string from the monad. This is because the`IO`

action doesn’t actually have a string to give you—it only represents a computation that returns a string. When you`bind`

a function`f`

to this monad, you’re building a new`IO`

action that asks the user for a string and then calls`f`

on it.

To summarize, monads let you change what it means to compose functions together. You might want to keep track of some extra information, store the functions in a tree, call them in a different order, call them multiple times, skip some functions entirely (based on the value being passed to them), etc.

You don’t have to use them, but now you don’t have to fear them either!

*EDIT: Fixed a typo and added the*

`MaybeMonad`

example at /u/wargotad’s suggestion.