Monads as Overloadable Semicolons
A comment by Heinrich Apfelmus on a post by Eric Raymond:
"A simpler way to think about monads is as a hack to turn function composition into a way of forcing the sequencing of function calls, or the functional-programming equivalent of a shell pipeline."
This is probably a good first mental approximation of the IO monad, but it’s not a good way to think about monads in general. They are best understood as imperative mini-languages where you can program your own semicolon “
;
“. The selection of possible side-effects is huge: state, logging, exceptions, non-determinism, coroutines, … . In particular, non-determinism does not fit the “ensure evaluation order” picture.The equivalent of a shell pipeline is plain function composition
(.)
coupled with lazy evaluation, at least if the shell commands are essentially side-effect free.
And a comment by Paul Johnson on the same post:
Its important to distinguish between the definition of a monad (roughly, its a type with a couple of operators defined) and the several ways that monads are used in Haskell.
*One* of those ways is to sequence several operations in some context, and one of those contexts is “IO”. This is indeed a neat hack, but the big news is that monads are not just a way to force IO semantics into a pure language, they are a way to introduce any kind of sequencing semantics you might want. Its a bit like having an overloadable semicolon; what do you want “{x;y;z}” to mean?
For instance, for one application I wrote a threaded discrete event simulation framework in Haskell using a combination of continuation and state monads with IO (because a suspended thread is actually just a continuation). This let me write application-level code with multiple threads where “delay (hour 1)” only delayed the thread long enough for the next hours-worth of simulated events to happen in other threads, rather than 1 hour of wall-clock time.
This is important because requirements are often expressed in terms of the form “do this, then do that”, where “then” has a domain-specific meaning. If you can capture that meaning in a monad then suddenly you have code that can be read and understood by a domain expert, which greatly reduces the opportunities for error.
Reader Comments