Monads: A Fence with the Silly Name
Functional programming advocates occasionally talk about something called a Monad. Should you make the mistake of asking what that means, you will get the most passive aggressive answer possible. It’s typically some blotch of words that presume your day job is in programming theory and wanted a concept you already understood explained to you. The thing is Monads are conceptually very simple: it’s a fence.
If you’ve ever used a Lisp-like language or a Scheme you might consider this to be a macro. And it’s true in practice–it’s a very formally defined kind of macro. Otherwise we have some work to do.
A Monad basically says “these inputs go in to the orb,” and “these outputs come back out of the orb.” Somewhere what the monad is actually for gets defined as the orb. Stuff happens inside the orb. Stuff that might not be functionally pure and could be deeply cursed. But like a Scheme macro the magic is contained inside the orb. Unlike a Scheme macro the inputs and outputs carry static type information. And if you don’t know what macros are–just think of it as things disappear in to the orb and come back out with the known shapes we’ve defined.
That’s it.
The IO Monad#
The IO monad in particular is a big lie: it represents the world outside of the pure mathematical world of functional programming.
Conceptually it represents “the entire world,” and it lets you print values.
Since printing is a mutation of world state, and functional programming performs mutation by getting a new house to paint before painting it, we actually end up with IO'.
Since the entire universe can’t really fit as something we keep copies of we simply lie about IO representing the current world state.
At the theory level this holds. If we could hold universes in RAM it would work exactly like everything else does–we just get a new whole universe every time someone eats a sandwich. But for pragmatic purposes we have to pretend that is what happens.
A convenient side-effect is that the IO monad requires the IO type.
This acts as a form of “capability” based programming.
If IO is not passed down, then the IO monad can’t be used, and thus functions cannot perform IO there.
So the monad it self defines the fence–input/output must happen inside the fence–but also requires the capability token to actually start writing.