After trying to join in on the monad jokes for forever, I opened up the the Wikipedia page on Monads (in the functional programming context, not the page in raw category theory) and it actually kinda made sense.
The problem that made monads make sense for me was when I had to chain (err, val) tuples for six or seven functions that only took val and handling the (err, _) bit was awkward. Someone showed how to rewrite it using monads to handle that without the boilerplate and voila.
I strongly suggest starting with a language like Elm to get into FP, since you start to use `map` and `andThen` quite often, but you also get sick of writing `a |> Result.andThen fn1 |> Result.andThen fn2`. This can help a programmer realize why it might be better to have a concise syntax for this, like:
myFun : String -> Result String Int
myFun a =
do b <- fn1 a
c <- fn2 b
return c
That said, I think the other problem with Haskell is the definition of the bind operator: it is not obvious to a beginner which concrete function is actually being called for each monadic operation. Idris2, for instance, lets you specify the bind operator in its do notation[0].
I think it'd become Just Another Monad Tutorial. Its something that clicks after a bit of FP programming without monads. Simon Peyton-Jones wrote a good paper about how IO worked prior to Monads which is nice - context helps with these things. I remember struggling to understand OO until I got my first junior dev role so I do think it's just practice practice practice to get through these things.
I like the way that "Learn You a Haskell" puts it:
"If we have a fancy value and a function that takes a normal value but returns a fancy value, how do we feed that fancy value into the function?"
That's basically all a monad is. If you know what map() does (in Haskell terms, map is a "functor"), then you know what a monad is, as it's just a fancy map().