What A Monad Is
A monad is an interface of 2 functions where 3 laws are satisfied. These 2 functions are:
These 3 laws are:
- Left identity
- Right identity
In Haskell, we might choose to represent the interface as the following.
Here I’m referring to
return and to
>>=. These names are the typical way to refer to these concepts in Haskell programming.
It’s important to understand that these types alone are not what make something a monad. A monad is more truly defined by it’s laws. What the laws mean in this context follows.
Actually, it’s hard to see that these laws are even being satisfied so, let’s look at this in a slightly different way.
Ah, now we can see these properties far more clearly. The
>=> is called a Kleisli composition operator.
If you’ve made it to this point you may be thinking “Why? What’s the point of this?” The answer to that question is explored in Why We Need Monads but, to make this article complete I’ll say it here. It turns out monads are useful for managing side-effects in programs that are evaluated using normal order.
Well. This is exceptionally complicated. This is truly confusing. How can one make sense of this? Unfortunately, the only way is practice. You won’t fully understand monads by reading this article. There’s no royal path to geometry and, there’s no royal path to monads.
With this being the case it would be useful to know what monads aren’t. Monads aren’t a design pattern. Monads aren’t a typeclass. Monads aren’t incomprehendable. What makes something a monad, principally, are the 3 monad laws. The type of unit and bind necessarily come from the monad laws. However, it’s important to realize that the type alone isn’t enough for something to be a monad. Indeed, one can implement the monad interface and, not have something that satisfies the monad laws. For this reason it’s also not a design pattern.
What monads are like is a more structured form of currying. It’s a form of composition. A monad, by itself, preforms an action. These actions can be bound together with the bind operation. In similar kind to how 2 functions can be composed together. What makes it possible to bind these operations are the monadic laws.
The IO Monad
It would be useful to see the underpenning of a monad. It’s been said that the IO monad is special. It’s been said that it’s a monad that’s internal to the compiler and, can’t be implemented by a typical program. Not only is this untrue but, the IO monad is in fact the simplest monad which exists. To that end, let’s implement the IO monad.
That’s it. That’s all the IO monad is. It’s literally just it’s construction and no more. With this we can use functions with side effects. Let’s take a look at that.
Here we’re calling out to some C code and, wrapping the results of the call in our monad. That’s all we have to do. Let’s use this. Let’s get a character from stdin and write it back to stdout.
Here I have 3 ways of doing the same thing. The top-most example is the most sugared. The bottom-most example has no sugar. The unsugared example is the most useful to us since this is what will actually be evaluated. We evaluate from left to right. So, evaluate
get. Then evaluate
put with the value of
get. That’s not so bad. Let’s look at a more complicated example.
Now this is interesting. The top example looks just like an imperatively defined program but, our desugared version is clearly just one expression. Evaluating this expression will be hard so let’s walk through it in pieces.
That’s it. That’s really what the IO monad is. Now, it’s significant to note that Haskell’s evaluation is memoized. That has consequences for functions with side-effects. But, this isn’t much of a problem. You could imagine a version of
foreign import ccall that doesn’t memoize it’s results. Indeed, Haskell’s IO monad doesn’t memoize it’s results.
So, what’s a monad? It’s complicated. It’s defined by abstract properties but, it can be useful for achiving certain results as was shown here.