Update: I started reading up on monads again recently, and here is the best explanation I’ve found. Also, the update caused my Beckman links to vanish unfortunately…
I’ve been digging through the Haskell resources I posted earlier (and some other ones ), and I must say that treatment of monads has been pretty poor. There are all kinds of cognitive metaphors out there, the least clear and most ridiculous of which has to be the space station analogy. However, I think after seeing a few key resources the picture is starting to come together.
First is a great pair of videos from Microsoft’s Brian Beckman. It’s geared toward concurrency, but he talks about Haskell’s State monad as a way of automatically mutating an explicit (vs implicit) state. Doing this non-monadically would mean passing in the current state into each function, but with monads, you can construct larger operations by composing the monads together, and the monads will handle all the work of passing around and updating the state.
The videos are pretty long, but quite interesting and really help to introduce the way a particular monad (the State monad) handles compositing.
The next resource is Monads as a computation. This page generalizes the concepts introduced in the videos. Essentially, monads a way of describing how computations are chained together to form more complex computations. The logic of what happens between computations (such as pre- and post-processing) before moving on to the next step is built into the monad (specifically the return and >>= functions).
Lastly, Learn You a Haskell (which, incidentally, I’m beginning to like more than RWH as the concepts get more sophisticated) has a chapter on monads, which goes in to how Maybe and List monads handle their own processing between steps. For instance, if at any point in a Maybe monad chain Nothing is the result, then that Nothing is propagated to the end of the chain (canceling later computations on the way).
From my understanding of monads (so far), they are a convenient way to automatically handle any book keeping that needs to be done between successive operations (Writer monad, which can be used to log all operations performed) or for controlling the flow of operations in a standardized way (aborting operations with Maybe, handling list flattening with List).