[Haskell-cafe] Re: Practise fingerspelling with Haskell! (Code cleanup request)

Paul Johnson paul at cogito.org.uk
Fri Jul 20 14:27:37 EDT 2007


Dougal Stanton wrote:
> I think I will have to, sooner or later, become more versed in the
> subtle ways of non-IO monads. They seem to be capable of some
> seriously tricksy shenanigans.
Keep trying.  At some point you will achieve enlightenment in a blinding 
flash of light.  Then you will write a monad tutorial.  Everybody 
learning Haskell goes through this.

In the hope of helping, here is *my* brief tutorial.  Monads capture the 
pattern of "do X then Y in context C".  All other programming languages 
have a single fixed context built in, and almost all of them use the 
same one.  This context is the reason that the order of X and Y matters: 
side effects are recorded in C, so stuff that happens in X is going to 
affect Y. 

Pure functions have no context, which means that X cannot affect Y (no 
context to transmit information).  Which is great unless you actually 
want to say "do X and then do Y".  In order to do that you need to 
define a context for the side effects.  Like I said earlier, most 
languages have exactly one context built in with no way to change it.  
Haskell has that context too: its called IO (as you may have guessed, 
these contexts are called "monads" in Haskell).  The thing about Haskell 
is that you can substitute other contexts instead.  Thats whats so great 
about monads.  But since you have only ever programmed in languages that 
have the IO monad built in, the idea of replacing it with something else 
seems very strange.

Ever programmed in Prolog?  The backtracking that Prolog does is a 
different way of propogating side effects from one step to the next.  
Prolog provides a different context than most languages, and in Haskell 
you would describe it using a different monad.  However because Prolog 
doesn't have monads it wasn't able to handle IO properly.  Hence a 
backtracking computation with side effects in Prolog will repeat each 
side effect every time it gets reached.  You could actually describe 
this in Haskell by defining a new monad with a backtracking rule but 
based on IO.  Or you could have a different monad that only executes the 
side effects once the computation has succeeded.

Each monad has two functions; "return" and ">>=" (known as "bind").  
"return" says what it means to introduce some value into the context.  
Its really just there for the types, and in most cases its pretty 
boring.  ">>="  describes how side effects propagate from one step to 
the next, so its the interesting one.

The final (and really cool) thing you can do is glue a new monad 
together using "monad transformers" as a kit of parts.  A monad 
transformer takes an "inner" monad as a type argument and the bind 
operation describes how effects in the inner monad are propagated in the 
outer monad.  Thats a bit more advanced, but when you come to create 
your own monads its generally easier than building from scratch.

Now I suggest going to 
http://en.wikibooks.org/wiki/Haskell/Understanding_monads and see if it 
makes any more sense.  Ignore the nuclear waste metaphor if it doesn't 
work for you.  The State monad is described about half way down, so you 
might think about that.  State takes a type argument for the state 
variable, so side effects are restricted to changes in that variable.  
Hence "State Integer" is a monad with a state consisting of one 
integer.  You might like to consider what could be done with random 
values in "State StdGen".

Hope this helps.

Paul.



More information about the Haskell-Cafe mailing list