So let’s remove the mystery from the monad, let’s break the abstraction and look into the representation:
The stateful monads:
type ('a,'s) reader = Reader of ('s -> 'a)
type ('a,'s) writer = Writer of ('a * 's)
type ('a,'s) state = State of (('a * 's) -> 'a)
The Continuation monad:
type ('a,'r) cont = Cont of (('a -> 'r) -> 'r)
A partial monad:
type ('a,'e) partial = Ok of 'a | Error of 'e
A non-deterministic monad:
type 'a nondeterm = Nil | This of 'a * 'a nondeterm
As you may see many of monads, are indeed closures underneath the hood. This shouldn’t surprise us, as monad is a functor and a closure is a versatile tool, in fact, you can implement all data structures, like list, option, map, etc using only closures. You can even go further and implement natural numbers as functions.
So why do we need a mysterious monad instead of closures? All the data types above can be circumscribed by the concept of a monad. You may see, that the representations are rather different, so we can’t actually generalize it using some mechanism of a language, e.g., parametric type, or functor, or anything like this. However, people noticed, that in all cases we use the same pattern: we have a return function of type
'a -> 'a t and a bind function, that has type
('a -> 'a t) -> ('a t -> 'a t) (alternatively, we can find a join operation as more natural, i.e.,
a t t -> 'a t).
Thus a monad is just a software design pattern, that may have different implementations, including closures, trees, lists, whatever. Unlike most design patterns, which you are usually implementing from scratch, Monad already has a few prebuilt implementations that you may tailor to your needs, so it’s quite rare when you really need to build your own monad from scratch. The Monads library provides a set of parametrized monads that should cover like 99% of needs. Though it would be never complete because the concept is very generic.
In other words, a monad is an abstract algebraic structure, like a group. A group is a set equipped with one commutative operation, that has certain properties. A group has an infinite number of implementations, as simple as natural numbers with addition or multiplication, and as complex as Galois and Lie groups. The same is the monad structure, it is a set of functors T on category C (category of values) equipped with two operations a
unit operation that brings a value into the monad, of type
C -> T(C) and a join operation that collapses the monad
T(T(C)) -> T(C), and two rules that require associativity and the identity of the unit element. This gives us a very general and abstract definition, and many actual theories fit nicely into this abstraction and have these properties. A way to understand this abstract definition is to think of monads as computations that yield values of type
C. The join operation defines the reduction rules, and the unit operation embeds values into pure computations (
pure is yet another synonym for
return, as well as
unit). This idea fits nicely into a substitution monad (the one that is not in the Monads library), that defines a small step (reduction) semantics of some expression language.
To summarize, a monad is an abstract structure. Recognizing that some algebra is a monad, allows us to express concisely the properties of the structure. But more important, is that every abstraction opens an avenue for generalization. We can take an algorithm and generalize it with a monad, without even knowing what this monad would be, except that it would be a structure that obeys certain rules and have the specified signature. This makes our algorithm applicable and reusable and many very different contexts.