> I mentioned this article in the retreat
I seem to remember reading something very similar a while back.
Unfortunately, he doesn’t understand monads, as far as I can tell. They were a solution to syntactic problem, not a semantic program.
Almost every language out there attaches a continuation to each statement, that is, a “next in time will be this” pointer. Some languages, like Scheme, give you access to the continuation. Most don’t. They all have it, though. Even Prolog and ML have them.
The pure functional languages can be regarded as an experiment in cutting off the continuations. All you are guaranteed is that any value you use was evaluated before you used it. So how do you do sequential computation? Use a value which was produced by the thing you want to have happened before you in time. If you look at Mercury, which is a really fast, pure, strongly typed Prolog, you find a lot of statements are rather different from traditional Prolog. print, for instance, takes a value of type IO () as well as the string to print, and returns a new value of type IO (). The IO () value you pass it is what was supposed to come before it in time. The IO () it returns is a value that lets another function inject itself into print’s continuation.
Remember how your thinking inverted when you learned Lisp, and suddenly you pulled values through functions instead of pushed them into variables? Same thing here. You construct the continuation as a sequence of nested statements instead of constructing statements as a sequence of nested continuations.
The thing is, passing that extra state variable around is bloody annoying. It makes code ugly. And if there’s anything a programming language researcher hates more than ugly code, I don’t want to see it.
Then Phil Wadler figured out that what he really wanted to do was to reprogram the boundaries between statements, and then found that a category theoretical construct called a monad nicely described the IO case. And a bunch of others. Though it turned out not to be right for a bunch more, which lead to the propagation in the community of applicative functors (aka, idioms) and arrows.
He mentions actors as a better idea than monads. Actors have their own problems, though. Yes, they are more intuitive initially, but reasoning behaviorally about concurrent systems doesn’t actually pan out. For instance, see Lamport’s commentary on a paper he ended up on the author list of with Dijkstra.
The reason monads took off is not because they were the undeniably best way of handling state threading. Clean, for instance, uses a completely different mechanism that works just fine. Monads took off because they compose. You can construct domains specialized for what you want to do.
The tools for doing this composition work well enough for production use, but are anything but elegant. As soon as anyone has a good idea on how to do it right, it will sweep through the Haskell community like wildfire.