A monad is any construct of abstraction that obeys the Monad Laws. This may seem a useless definition, but my point is that deriving a useful intuition for the concept of the monad is necessarily challenging because they cannot readily be boiled down any further than that without loss of information.
The best intuitive explanation I've developed so far is that a monad is an abstraction over structures of ordered computations. The most ready examples for non-functional programmers are probably exceptions (and their handlers) and nullable types (typically called "optional types" in languages with first-class handling of such things, unlike Java).
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
pure x = Just x
Nothing >>= f = Nothing
Just x >>= f = f xYou don't need List<A> to write an IntList, nor do you need + to work on different integers in order to have a particular integer.
Otherwise memorize a little bit and dispose of the mystery. It’s not that far out.
ArrayList's kind is type->type
ArrayList<A>'s kind is type.
The A is what plugs into type on the LHS of the arrow, leaving only the RHS remaining.
Huh, I thought a monad is just a monoid in the category of endofunctors, what's the problem?
In both cases what they really are is an abstract concept defined by things that satisfy some definitions, but in practice it's easier to just look at a few concrete examples like Maybe.
I will say that explaining functors to my coworkers was always much simpler, and then naturally led to monads
For haskellers, it is writing a monad tutorial
For javascripters, it is writing a framework
For make-stuff-with-LLM people, it is producing a diagram explaining your code generation factory
... and so on
I still have an old book Putting Metaclasses to Work - A New Dimension in Object-Oriented Programming by Forman et.al somewhere.
There is also the classic The Art of the Metaobject Protocol by Kiczales et.al which is quie relevant here - https://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Prot...
The key difference is that the Type guys do it at compile time (correctness) while the OO guys do it at runtime (flexibility).
I like monads as a concept, but in practice I find them frustrating and unnecessarily complicated. I worked on a large game written in Haskell and eventually gave up because dealing with monads made development so cumbersome.
I love the idea, but for real-world projects I’d rather avoid the complexity.
You start from a functor which is a data type that admits a map operation.
Then you add of, or pure, to make an applicative functor, and then you add flatmap to make a monad.
Namely, the section on "Mapping knowledge webs" (around 3:33). It explains people can struggle to adopt concepts that are too far outside their current knowledge, but that it can still be possible for them to pick it up if they can build a path to it from their current knowledge. (This often presents itself as the "depth-first" learning style)
A lot of commenters here, talking about how monads are so simple and how not being able to learn them is just lazy, are misunderstanding how learning fundamentally works. You have to expand the knowledge graph in the direction of monads before it will be easy to pick up monads. You have to build a path. You cannot simply teach monads right off the bat and expect someone to intuitively "get it". People who intuitively "get it" are people who already have a path.
But in practice, I think monads are a poor tool for large-scale software development. I spent a long time trying to build a large game in Haskell and eventually gave up out of frustration with the complexity they introduced.
Monads make sense as a way to manage effects in pure languages like Haskell/Lean/Idris/Agda. But outside that context, I don’t think the additional abstraction is worth the cost.
Understanding how monads work is one thing. Understanding why they’re needed in the first place, and when they’re not, is another.
What sort of situations would you want to give up a little purity or error handling at the type level? Maybe at a boundary where you can just write a very ugly imperative but quarantined section to give it a simpler type?
That's quite a hateful way to describe lack of knowledge.
There are some prerequisites that make it easier to understand monads, and a lot of programmers don't even know those. That can make learning monads difficult right off the bat.
It's really basic concepts, much easier than the analysis you do in high school.
But people would rather sit through monad as boxes or burritos cringe tutorials.
Your next step could be to blame the school systems if you want, but that doesn't help the situation at hand.
> Your math explanation starts with a math concept that the vast, vast, vast majority of people will have never even heard of, even in math-adjacent fields
Let me take this apart.
1. a data type that admits a map operation
Present in most languages including JavaScript. Not a mathematical issue.
2. add of, or pure, to make an applicative functor
I had to look this up. It was new content for me, maybe 5 or 10 minutes believing I would get it.
3. add flatmap
This didn’t scare me but maybe it scares others. Not a mathematical issue here, though. Being in C++ doesn’t make this concept mainstream, I guess?
It's a pair of a type constructor F(a) and a map operation a -> b to get an F(b).
The two "non-trivial" details are the fact that the map operation has to respect identity, map(id) = id, and function composition: map(g ∘ f) = map(g) ∘ map(f)
None of those concepts is any difficult, nor requires any "math major" or non-trivial details, because the are not there.