On another note, I suspect that the main problem everyone faces when explaining monads to someone who is not familiar with the term is "caused" by the dominance of C++-like programming languages.
Monads and functors are not really all that complicated per se, but because C++ templates and Java-style generics are not able to operate at their level of abstraction, people that are only used to thinking in these terms fail to map them into their "comfort zone" and usually give up. And instead of pointing out that monads are on a higher abstraction level, you get statements like "monads are like burritos"[1] which only confuse people further.
The explanation that finally made sense to me was when someone didn't only explain things in the abstract and them link them to the next ridiculous non-programming thing, but instead laid out the basic operations and then pointed out that options, lists and asynchronous tasks are monads because they support those operations. I was basically in the exact situation you describe.
Of course, that people can't agree on a single terminology to save their lives doesn't help either (return vs. lift, bind vs. flatMap vs. SelectMany). From the outside it's like one of those math papers where you spend a day figuring out which non-standard notation they used in order to understand the equations in it.
> because C++ templates and Java-style generics are not able to operate at their level of abstraction, people that are only used to thinking in these terms fail to map them into their "comfort zone" and usually give up.
That's what "patterns" are for, in C++/Java and any low-level languages that don't provide the level of abstraction you're after. Functors and monads are patterns in these languages, just like subroutines are a pattern in assembly language but not in C, and "objects" or "closures" are patterns in C but not in C++/Java. Monoids are usually called the "Composite pattern", hence saying that monads are monoid objects is just stating that they share analogies with the Composite pattern at a higher level of abstraction. So what's the problem?
> That's what "patterns" are for, in C++/Java and any low-level languages that don't provide the level of abstraction you're after.
Keen observation. If you read through most explications for monads that float around the internet, though, you will find that design patterns are usually introduced to the reader with much more didactic care. Texts explaining, say, the Command Pattern will usually try to lead the "average" (or even junior) Developer to understanding by providing motivation ("let's write an Undo feature!"), introducing new concepts in the context of some simple, but usually tangible scenario ("let's say we have this editor…") and explain things in terms of the stuff the reader can be assumed to know already.
Even if you look for explanations of monads aimed at non-FP developers, usually they start with something like "For some monad `M`, …", followed by either mathematical expressions or some very abstract function signatures in Haskell (which a majority of readers has probably never seen before). At that point, you already have lost 90% of the audience.
I have yet to try to explain the concept to an unsuspecting colleague, but if I were to try, my approach would be to start with familiar things. For a C# dev, this could be LINQ, for example. In this case, you could even get people pretty far, since the inline query syntax is pretty much just a do notation that was bludgeoned with an SQL hammer. If you then point out how other things than IEnumerables and IQueryables (IObservables or Tasks, for example) work in similar ways and could be treated the same way, I suspect you should be able to nudge the average C# dev along far enough to give them a basic understanding of the concept and some of the upsides without instantly resorting to single letter type signatures.
But some patterns are easier to understand than others.
Most are created through experience gathered while programming and are rather parctical solutions to frequent problems.
Mathematical concepts are patterns too, but they were often "developed" by people who had nothing to do with day-to-day programming challanges and seem rather foreign for the average developer.
Someone said "Functors are objects with a map method, monads are objects with a flatMap method" and then explained some different type of objects that have these methods and how the work in that specific cases.
After 2-4 cases I saw the principles and rules behind them.
Monads and functors are not really all that complicated per se, but because C++ templates and Java-style generics are not able to operate at their level of abstraction, people that are only used to thinking in these terms fail to map them into their "comfort zone" and usually give up. And instead of pointing out that monads are on a higher abstraction level, you get statements like "monads are like burritos"[1] which only confuse people further.
The explanation that finally made sense to me was when someone didn't only explain things in the abstract and them link them to the next ridiculous non-programming thing, but instead laid out the basic operations and then pointed out that options, lists and asynchronous tasks are monads because they support those operations. I was basically in the exact situation you describe.
Of course, that people can't agree on a single terminology to save their lives doesn't help either (return vs. lift, bind vs. flatMap vs. SelectMany). From the outside it's like one of those math papers where you spend a day figuring out which non-standard notation they used in order to understand the equations in it.
[1]: https://blog.plover.com/prog/burritos.html