upvote
The problem is not monads. Any programmer understands the need to represent "the world". It is the need to keep that representation modular that leads to monad transformers, which makes regular people (like me) simply check out and go back to C++

https://en.wikipedia.org/wiki/Monad_transformer

reply
Monads have no inherent connection to any notion of "the world"; that's just a thing for Haskell's IO monad specifically (and perhaps derivatives thereof) because what that abstracts over is effects that are external to the program.

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).

reply
Not sure if going back to C++ is the answer, given how much Haskell like code one can write since C++20, and it has gotten even better with newer standards.
reply
That may be true for functions which operate on a generic Monad typeclass, but typeclasses (Higher kinded types) aren't required to implement concrete Functor / Applicative / Monad instances for a particular type, e.g. Maybe:

    fmap f Nothing = Nothing
    fmap f (Just x) = Just (f x)

    pure x = Just x

    Nothing >>= f = Nothing
    Just x >>= f = f x
reply
"Generic" and "for a particular type" cancel out.

You 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.

reply
Agreed. But there's a big difference between parametric polymorphism (List<A>) and ad-hoc polymorphism like typeclasses. It would be very painful to have to write a new list type for any kind of value type it might hold, but with monads you have many fewer distinct implementations (mainly just Maybe / Either / List / State / IO) and their actions are so different that you almost have to know exactly which monad you are using in the code, so "generic" code that can operate with any monad is less useful.
reply
When people say they don’t understand Monad, my first assumption is that they are wearing their ignorance as a badge of honor.

Otherwise memorize a little bit and dispose of the mystery. It’s not that far out.

reply
It seems that in java you could write `ArrayList<A>`. I think this type is actually of kind "type -> type". But in java it seems that we cannot have the type `A<B>`, and functors and monads require that..
reply
Just to polish that,

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.

reply
I think most of the difficulty in explaining monads is the IO monad specifically. Leave that off and monads seem almost trivial. Add it back and whatever trivial mental model you just built stops working altogether.
reply
> things that makes monads notoriously difficult to explain to people outside of the Haskell ecosystem

Huh, I thought a monad is just a monoid in the category of endofunctors, what's the problem?

reply
It's about as difficult as describing vectors in math. Vectors aren't really "little arrows" or "things with magnitude and direction" (because then functions wouldn't count), I think there's a similarly cryptic saying that "a vector is just an element of a vector space" or "a tensor is anything that transforms like a tensor".

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.

reply
And here I was convinced that they’re burritos!

I will say that explaining functors to my coworkers was always much simpler, and then naturally led to monads

reply
I suspect all branches of tech have their rite of passage.

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

reply
deleted
reply
Some OO languages have a parallel concept in "Metaclass" (https://en.wikipedia.org/wiki/Metaclass) i.e. the class of a class which is structurally similar to "Kind" though of course the mechanics are quite different.

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).

reply
No, monads are largely a solution to problems introduced by pure functional programming, problems that impure languages don’t have in the first place.

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.

reply
The thing that makes monads difficult is laziness and the anti math circle jerk.

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.

reply
It's odd, the stereotype of software developers is a know-it-all attitude, but start talking about types and you get excuses that boil down to 'I'm incapable of learning to understand the thing you learned to understand'.
reply
There is a video called A New Programming Fundamentals Course that contains some concepts that are very helpful to understand cases like these. I'd recommend you watch, it's free: https://www.youtube.com/watch?v=EV13CNrq4ZA

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.

reply
I used to be a big Haskell fan and had a lot of fun writing and using monads. And I agree that once you get them, the basic idea is quite simple. I’ve even used monads to prove a small compiler correct in Lean.

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.

reply
OCaml isn't pure and neither is F# iirc do you see a bit less monad heavy code in large codebases there?

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?

reply
> The thing that makes monads difficult is laziness and the anti math circle jerk.

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.

reply
No there's no complexity behind monads except laziness and anti math circle jerk.

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.

reply
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. It's not anti-math reasoning. It's a lack of self-awareness that your background is very math heavy, which makes that particular explanation make sense to you. I've gone my entire schooling, as a student who was always one of the few who were "good at math", all the the way through my CS education, without ever having heard of a functor until I came across the Haskell monad explanation meme.

Your next step could be to blame the school systems if you want, but that doesn't help the situation at hand.

reply
>> 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.

> 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?

https://en.cppreference.com/cpp/container/flat_map

reply
I majored in mathematics and I learned category theory before touching any serious Haskell, and I still found most of the "monad tutorials" kind of opaque and handwavy, and I think there are inherently non-trivial details unrelated to the notion of functor etc.
reply
No there are no trivial details, and you don't need a mathematics major or category theory to understand what a functor is.

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.

reply
When there are 100 explanations of some topic, maybe it's not so trivial, after all, even when the bare axioms seem trivial.
reply
Most of the stuff you just explained is absent from your explanation of monads. So it turns out monads are not so simple after all for people who don't already understand functors...
reply
FWIW I dropped out of high school to pursue programming more directly. I regret it now because of the job market crash, but it's also too late for me to go back.
reply
deleted
reply
Lack of knowledge is not the problem at all. Anti-intellectualism is.
reply
You can try to blame lack of knowledge on anything you want, but at the end of the day Hacker News is for intellectual curiosity and even HN readers don't all know what monads are.
reply
I think you missed the “not”.
reply
Nope.
reply