(2) Monadic programming gets hard to understand if you can't cleanly split out functions into having just one argument and one output.
Translation for people who don't know what a "monad" is: occasionally there are type-adjectives (I'll use the example "blue") where there is a canonical way to make any object into a blue object (called `return`), and a canonical way to make a blue 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 blue objects to blue objects (called `fmap`).
One example is the adjective "either an X or a ____", which is written in Haskell as `Either x`. The canonical way to take a Y and `return` it into "either an X or a Y" is to say "it's a Y -- the type on the right." In Haskell we'd say that `data Either x y = Left x | Right y` and that this `return` function is `return y = Right y`.
Similarly the canonical way to map a function `y -> z` over such an `Either x y` to get an `Either x z` is "if the value is an X don't do anything, otherwise do the function to the value and collect the end result." This is written `fmap zy exy = case exy of Left x -> Left x; Right y -> Right (zy y)`. Finally, the canonical way to take an "either an X or an (either an X or a Y)" into "either an X or a Y" is just: if you've got an X, it's an X; if you've got a Y, it's a Y:
join ex_exy = case ex_exy of
Left x -> Left x
Right exy -> case exy of
Left x -> Left x
Right y -> Right y
So it'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 -> y` and apply it to an `m x` to make an `m y`].Haskell became obsessed with them because this structure describes computer programs really well. Suppose you build in a data type for "a program which produces a...". Then the basic "program composition" operator looks like this:
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.
The type signature here is `(IO x, x -> IO y) -> 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 -> IO y` on the `IO x` to produce an `IO (IO y)`, then `join` the programs to produce an `IO y`. "A program which produces a ..." is thus a special case of a monad, an adjective which supports these three operations (`return` is "produce a program which does nothing and yields this Haskell value").
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/O.
So the translation of the above points is that (1) this whole process gets confusing if you don't know the difference between a wagon, a blue wagon, and a blue blue wagon at compile time, and the tendency in a Lisp is to say "I saw a wagon, I wanted a blue something, so let's just quietly use the `(paint-blue wagon)` subroutine to keep going," and "I saw a blue blue wagon, I wanted a blue something, so I am happy." 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't even clearly articulate what `fmap` does unless you can cleanly say "I have a function from wagons to wheels, and I want the corresponding function from blue wagons to blue wheels." If your functions are taking a bunch of extra parameters, like a wheel-index of "front-left, front-right, back-left, back-right" then it gets hard to say "here's the wagon input that I want to become a blue wagon input, please leave my wheel indexes alone!"