[Haskell-cafe] Monads and Functions sequence and sequence_

Roman Cheplyaka roma at ro-che.info
Sat Oct 30 09:07:06 EDT 2010


* Mark Spezzano <mark.spezzano at chariot.net.au> [2010-10-30 15:37:30+1030]
> Can somebody please explain exactly how the monad functions "sequence"
> and "sequence_" are meant to work?

The others in this thread have already explained how these functions
work, so I'll just give an example how they are used.

Consider the following task: to read 30 lines from standard input.
For one line you would use an action

  getLine :: IO String

How to execute this 30 times? Haskell has a function

  replicate :: Int -> a -> [a]

which takes a number and produces a list with that number of
identical elements.

So this is close to what we need:

  replicate 30 getLine :: [IO String]

This is a list containing 30 'getLine' actions. But the list of
actions _is not_ an action itself. This is what sequence does -- it
transforms a list of actions into a single action which gathers the
results into one list. As its name suggests, it does sequencing of
actions.

  sequence $ replicate 30 getLine :: IO [String]

Exactly what we need, an action producing a list of lines read.

Now, let's consider this code:

  sequence [ putStrLn $ show i ++ " green bottles standing on the wall"
           | i <- reverse [1..10] ] :: IO [()]

This action prints 10 lines and also returns us gathered results, i.e.
10 '()', one from each putStrLn (recall that putStrLn has type "String -> IO ()".

Most probably we don't care about those '()', but they still occupy
memory and introduce a space leak as explained here[1]. That's why a
version of sequence is introduced which ignores the results of actions
and simply returns (). It is called "sequence_".

  sequence_ :: (Monad m) => [m a] -> m ()

As a side note, we can rewrite our last example without using list
comprehension in the following way:

  let p i = putStrLn $ show i ++ " green bottles standing on the wall"
  in  sequence_ $ map p $ reverse [1..10]

The combinations of sequence and sequence_ with map are so common that
they have special names:

  mapM  = \f -> sequence  . map f :: (Monad m) => (a -> m b) -> [a] -> m [b]
  mapM_ = \f -> sequence_ . map f :: (Monad m) => (a -> m b) -> [a] -> m ()

[1] http://neilmitchell.blogspot.com/2008/12/mapm-mapm-and-monadic-statements.html

-- 
Roman I. Cheplyaka :: http://ro-che.info/
"Don't let school get in the way of your education." - Mark Twain


More information about the Haskell-Cafe mailing list