[Haskell-cafe] do

Luke Palmer lrpalmer at gmail.com
Sat Oct 13 19:33:00 EDT 2007

Disclaimer:  I'm explaining all of this in terms of "actions", which
are only one way of looking at monads, and the view only works for
certain ones (IO, State, ...).  Without futher ado...

An action does two things:  it has a side-effect and then it has a
return value.  The type "IO Int" is an I/O action which does something
then returns an Int.

(>>) :: m a -> m b -> m b

x >> y  first does x, *discards* its return value, then does y.  You
can see that the return value of x is discarded by the absence of the
type variable a in the return value of (>>).  So if you said:

    getLine >> putStrLn "Hello"

This is an action which gets a line from the user and then throws it
away, never to be retrieved again, only to print Hello.

(>>=) :: m a -> (a -> m b) -> m b

But what if you want to do something with the return value?  That's
what (>>=) is for.  (>>=) takes an action on its left side and a
function which returns an action on its right, and then "pipes" one
into the other.

    getLine >>= (\x -> putStrLn x)

This gets a line from the user and then executes the function on the
right given the return value from getLine as an argument; i.e. x is
bound to the return value of getLine.  The above can also be written

    getLine >>= putStrLn

Because of currying.  This action echoes one line.

Using this you can do more complex actions, like, for instance, adding
two numbers:

    readLine >>= (\x -> readLine >>= (\y -> print (x + y)))

Take a moment to grok that...

Which you might like to write:

    do x <- readLine
       y <- readLine
       print (x + y)

The parser sequencing thing is probably from the List monad (unless
you're using Parsec or something).  List was the first monad I really
understood (before IO even), thanks to this great tutorial:



More information about the Haskell-Cafe mailing list