Anyway, I understand.
> I am going to be assuming some familiarity with monads (and to a certain extent, do notation). There are enough introductions to monads out there as it is.
Personally, I think that monads are a sore spot for functional programmers, because they are the crux of why FP runs into difficulties in the real world when dealing with things like mutable state, side effects and logic that happens over multiple steps (imperatively).
Here is a relatively nontechnical discussion about how monads bridge functional and imperative programming, by treating IO sort of like an imaginary number that can be passed along as a black box until it can finally be computed:
Instead monads are used to unify the foundation of many types: options, lists, trees, etc. Also monads are really nice for futures and parsers.
The point I’m trying to make I guess is that monads are very useful for other things than dealing with impurity, which I think a lot of people just learning them miss.
For those who hadn't seen this before, here's an explanation: https://stackoverflow.com/questions/3870088/a-monad-is-just-...
But I'll give it a go, I suppose. A functor is a type that represents turning something into something else. For example, for example turning a List<Int> into a List<Double>.
A monad is a functor that also has a bind or flatMap method attached to it. Both essentially allow you flatten or "chain" the values inside. So the monad defines a way to map things (inherited from functors), and flatten things (via bind or flatMap depending on how you want to define it). Also you need applicatives, which is just a way to box things. i.e turning a Int into a List<Int>.
There are also some laws associated with them, but you probably get the idea.
Examples of useful monads: lists, options, futures, database transactions, logging, parsing, etc.
Applicative functions do have that property, but their key attribute is the ability to two things together, e.g. turning a List<Int> and a List<Double> into a List<Pair<Int,Double>>. A functor which also has the ability to put arbitrary things into the functor context, but not the ability to combine two contexts, is sometimes referred to as a pointed functor. (There is no official Haskell typeclass for pointed functors; the main reason, besides historical baggage, is that non-applicative pointed functors don't have any real laws aside from the ones which apply to functors.)
Applicatives are sufficient for sequencing effects but the List<Double> in the previous example can't depend on the Int values in the List<Int>. This is great for static analysis of effects but it limits the kinds of programs you can write to those whose effects are known in advance. A monad lifts this restriction and allows effects (not just values) to be computed dynamically from the values of prior effects.
Finite[1] applicative parsers can only parse context-free languages. Monadic parsers, on the other hand, can handle context-sensitive languages (without resorting to an infinite set of production rules).
[1] https://byorgey.wordpress.com/2012/01/05/parsing-context-sen...