Something about learning what a monad is renders you utterly unable to say what a monad is. It’s a self-enforcing Fight Club.
Let’s assume you’re a programmer, and you’ve heard your coworkers toss around the term “monad” a few times1. They suffer from a deplorable inarticulateness when you ask about “monads”. So you go to Wikipedia, thinking you’ll find a primer. You won’t. As of the time of this writing, you’ll actually find something more like this.
In functional programming, a monad is a structure that represents computations defined as sequences of steps. A type with a monad structure defines what it means to chain operations, or nest functions of that type together. This allows the programmer to build pipelines that process data in steps, in which each action is decorated with additional processing rules provided by the monad.
And, I mean, that explanation really does say it all! If only you can understand what it means. I read the first sentence a few times, and I thought, Okay, well, isn’t that what a program is? A sequence of steps which defines a computation? You find yourself reading many words you’ve seen before, but filled with different meanings. You’ve set out to learn a new word, and now you find you’ve lost words you thought you already knew.
Like I said, though, it’s really all there. I’m not going to explain monads, but I’m going to supply a bit of context missing from every single discussion, tutorial, or other edifying material I’ve seen online and offline, and maybe this will help someone besides me out. The key there is really the first three words: in functional programming.
What they mean is a pure functional programming language, which is essentially just lambda calculus. Setting aside what lambda calculus is and why you might ever want to type it into a computer, the upshot of this purity concept is that things we take for granted while programming—assignment, exceptions, input/output, continuations, and so on—are no longer possible! They’re not pure.
Monads therefore exist to give a “pure” way to do all these things. It’s just a word for a tactic that solves all these problems in similar ways that don’t cause the language to become “impure.” Using this tactic, we can laboriously reconstruct many of the computational bits we’re accustomed to. While the concept dates from the early 90s, it’s found new life as we realize the advantages of stateless functional computations in concurrency programming contexts2.
For the nuts and bolts of how this tactic works, I found the best explanation were the earliest ones. I didn’t get any of the above until I read this whitepaper on the subject from 1992. Or this one by the same guy from around the same time. Seriously. Give it a shot if you’re struggling with this concept.