Thursday, July 27, 2006

the strain of a monad kick

I've been on a monak kick recently, i.e., reading some of the monad material lying around the Web in an attempt to wrap my gray matter around the concept. All about monads is good for its sheer thoroughness, and Monads as Containers makes a commendable effort to apply some analogies to it. This page about Haskell I/O takes a close, step-by-step look at why and how the IO monad works the way it does.

My own light bulb switched on (if it has!) when I realized that monads were like the formal symbol systems I learned in my abstract algebra courses (I was com sci major, math minor). Just as we can take a set of numbers, define some operations on that set which have specific properties, and then use those properties to combine operations, so we can do the same with a monad. Unlike the set of integers, which has numerical values and the (+) and (*) operations, a minimal monad has values of any specific type you choose and the "return" and "bind" operations or functions.

The return operation defines how to take a value that is not a monad and make a monad value out of it. The bind operation is trickier to understand, but basically it serves the purpose of constructing a new monad value from existing monad values. It takes for parameters a monad value and a function that creates a monad from an outside value, and returns a monad value by somehow applying the function argument to the monad argument. If the monad value was a simple list, for instance, the bind operation might just be applying the function to each element in the list and combining all the results into a list.

If I pass a monad value and a function to the bind operation, I will get back another monad value. (In abstract algebra we would say that the bind operation has closure.) This means that I can substitute a call to the bind operation anywhere that a monad value would work, such as, say, the monad value argument to a bind operation! I could say "monad bind function bind function bind function bind function". Each bind applies the function on the right to the monad on the left, so the monad on the left of each bind must be evaluated for the bind itself to be evaluated, so the sequence of the monad operations is assured.

The really interesting bit here is that the set of operators or functions for a monad can be put to use without knowing how the monad's bind or return are implemented. The Haskell folks have come up with many varieties of monads that can connect statements in ways that might make typical Haskell code sneer: IO, Continuations, exceptions, state. I haven't covered real examples of monads or transformers, and I don't plan to. I have satisfied my monad curiosity for right now.

No comments:

Post a Comment