(1) Monadic programming gets really hard to understand if you don&#x27;t have a strong type system correcting you when you screw up the difference between `x`, `m x`, and `m (m x)`. The tendency in weak type systems is to autopromote `x` to `m x` with `return`, but this can make it impossible to see if you need to deconstruct `m (m x)` to `m x` with `join` in any given application, unless you just auto-flatten everything, which sometimes (especially in the list monad!) is not what you want.<p>(2) Monadic programming gets hard to understand if you can&#x27;t cleanly split out functions into having just one argument and one output.<p>Translation for people who don&#x27;t know what a &quot;monad&quot; is: occasionally there are type-adjectives (I&#x27;ll use the example &quot;blue&quot;) where there is a canonical way to make any object into a blue object (called `return`), and a canonical way to make a <i>blue</i> blue object into a blue object (called `join`), and a canonical way to take some function from objects to objects and turn it into a function from <i>blue</i> objects to <i>blue</i> objects (called `fmap`).<p>One example is the adjective &quot;either an X or a ____&quot;, which is written in Haskell as `Either x`. The canonical way to take a Y and `return` it into &quot;either an X or a Y&quot; is to say &quot;it&#x27;s a Y -- the type on the right.&quot; In Haskell we&#x27;d say that `data Either x y = Left x | Right y` and that this `return` function is `return y = Right y`.<p>Similarly the canonical way to map a function `y -&gt; z` over such an `Either x y` to get an `Either x z` is &quot;if the value is an X don&#x27;t do anything, otherwise do the function to the value and collect the end result.&quot; This is written `fmap zy exy = case exy of Left x -&gt; Left x; Right y -&gt; Right (zy y)`. Finally, the canonical way to take an &quot;either an X or an (either an X or a Y)&quot; into &quot;either an X or a Y&quot; is just: if you&#x27;ve got an X, it&#x27;s an X; if you&#x27;ve got a Y, it&#x27;s a Y:<p><pre><code>    join ex_exy = case ex_exy of 
      Left x -&gt; Left x
      Right exy -&gt; case exy of 
        Left x -&gt; Left x
        Right y -&gt; Right y
</code></pre>
So it&#x27;s adjectives which are (a) universal [we can apply them to anything], (b) collapsible [we can take an `m (m x)` and turn it into an `m x` and (c) mappable [we can take an `x -&gt; y` and apply it to an `m x` to make an `m y`].<p>Haskell became obsessed with them because this structure describes <i>computer programs</i> really well. Suppose you build in a data type for &quot;a program which produces a...&quot;. Then the basic &quot;program composition&quot; operator looks like this:<p>First, take two inputs: (1) a program which produces an X, (2) a function which takes X and produces a program which produces a Y. Then, yield a program which will (when run) produce a Y by first running program (1), then using the X generated as an input to the function (2) to compute a program which produces a Y (3), then runs (3) to produce the y.<p>The type signature here is `(IO x, x -&gt; IO y) -&gt; IO y`. This curious function is called `bind` and it can be more easily thought of as a combination of two separate steps: `fmap` the `x -&gt; IO y` on the `IO x` to produce an `IO (IO y)`, then `join` the programs to produce an `IO y`. &quot;A program which produces a ...&quot; is thus a special case of a monad, an adjective which supports these three operations (`return` is &quot;produce a program which does nothing and yields this Haskell value&quot;).<p>And you care about all of this because being all indirect -like about computer programs allows you to metaprogram up an impure program in a pure language, which is how Haskell does I&#x2F;O.<p>So the translation of the above points is that (1) this whole process gets confusing if you don&#x27;t know the difference between a wagon, a blue wagon, and a <i>blue</i> blue wagon at compile time, and the tendency in a Lisp is to say &quot;I saw a wagon, I wanted a blue something, so let&#x27;s just quietly use the `(paint-blue wagon)` subroutine to keep going,&quot; and &quot;I saw a blue blue wagon, I wanted a blue something, so I am happy.&quot; You can force things to always use some `(coalesce-blue-paint ___)` function to always flatten blue-blue Xs into blue Xs, but this is usually counterintuitive. (2) You can&#x27;t even clearly articulate what `fmap` does unless you can cleanly say &quot;I have a function from wagons to wheels, and I want the corresponding function from blue wagons to blue wheels.&quot; If your functions are taking a bunch of extra parameters, like a <i>wheel-index</i> of &quot;front-left, front-right, back-left, back-right&quot; then it gets hard to say &quot;here&#x27;s the wagon input that I want to become a blue wagon input, please leave my wheel indexes alone!&quot;