Take the 2-minute tour ×

Whenever I read about Monad example, they always present IO as a case study.

Are there any examples of monads doing list manipulation which somebody could present? I aprpeciate this could be overkill, but I am interested if monads can present advantages over regular list manipulation techniques.

share|improve this question
[1..5] >> "Echo! " "Echo! Echo! Echo! Echo! Echo! " –  AndrewC Nov 5 '12 at 23:35
[0..9] >>= show "0123456789" –  AndrewC Nov 5 '12 at 23:36
add comment

6 Answers

up vote 7 down vote accepted

The big secret to the list monad in Haskell is that list comprehensions are syntactic sugar for do blocks. Any time you write a list comprehension, you could have written it using a do block instead, which uses the list monad instance.

A simple example

Let's say you want to take two lists, and return their cartesian product (that is, the list of (x,y) for every combination of x from the first list and y from the second list).

You can do that with a list comprehension:

ghci> [(x,y) | x <- [1,2], y <- [3,4]] -- [(1,3),(1,4),(2,3),(2,4)]

The list comprehension is syntactic sugar for this do block:

zs = do x <- [1,2]
        y <- [3,4]
        return (x,y)

which in turn is syntactic sugar for

zs = [1,2] >>= \x -> [3,4] >>= \y -> return (x,y)

A more complicated example

That example doesn't really demonstrate the power of monads, though, because you could easily write it without relying on the fact that lists have a Monad instance. For example, if we only use the Applicative instance:

ghci> import Control.Applicative
ghci> (,) <$> [1,2] <*> [3,4] -- [(1,3),(1,4),(2,3),(2,4)]

Now let's say you take every element of a list of positive integers, and replicate it as many times as itself (so e.g. f [1,2,3] = [1,2,2,3,3,3] for example). Who knows why you'd want to do that, but it is easy:

ghci> let f xs = [ y | x <- xs, y <- replicate x x ]
ghci> f [1,2,3] -- [1,2,2,3,3,3]

That's just syntactic sugar for this:

f xs = do x <- xs
          y <- replicate x x
          return y

which in turn is syntactic sugar for

f xs = xs >>= \x -> replicate x x >>= \y -> return y

This time we can't write that just using the applicative instance. The key difference is that we took the output from the first bind (x) and made the rest of the block depend on it (y <- replicate x x).

share|improve this answer
"The big secret to the list monad in Haskell is that list comprehensions are syntactic sugar for do blocks." The connection between comprehensions and do blocks is a good insight, but the statement here is not actually true. Comprehensions could be implemented as a translation into monads, but Haskell implementations don't have to do so, and GHC doesn't. As I recall, because of this, list comprehensions in GHC are noticeably more efficient than the list monad. –  Luis Casillas Oct 3 '12 at 16:41
@sacunim Wow, I didn't know that. But presumably the value of a list comprehension still has to be equal to the value of the corresponding do block? –  Chris Taylor Oct 3 '12 at 18:42
Chris, yes, and that's why I called your answer a "good insight." –  Luis Casillas Oct 3 '12 at 21:18
With the MonadComprehensions language extension, this correspondence goes the other way too! –  Ørjan Johansen Oct 5 '12 at 0:12
And also, if I recall, enabling MonadComprehensions removes that speed optimization of list comprehensions and you're back to list monad performance. –  Christopher Done Apr 7 '13 at 19:06
add comment

A classic example of using the list monad to cleverly write a "simple" list utility function is this:

import Control.Monad (filterM)

-- | Compute all subsets of the elements of a list.
powerSet = filterM (\x -> [True, False])

The type of filterM is Monad m => (a -> m Bool) -> [a] -> m [a]. In the context of the list monad, this is a nondeterministic list filter: a filter operation that takes a nondeterministic predicate that returns a list of alternative answers. The result of filterM is in turn a list of alternative possible results.

Or in simpler language, filterM (\x -> [True, False]) means: for each element of the list, I want both to keep it and throw it away. filterM figures out all possible combinations of doing this for each list element.

share|improve this answer
this is awesome! thank you. –  Will Ness Oct 4 '12 at 0:10
add comment

Here is a very stupid way to find pairs of divisors for a given integer:

divisors:: Int -> [(Int,Int)]
divisors n = do
  x <- [1 .. n]
  y <- [1 .. n]
  if x*y == n then return (x, y) else []

The meaning of this fragment ought to be fairly straight-forward. Obviously, this is a stupid way to solve this specific problem. (There are far more efficient methods possible in this case.) But now imagine some more complicated problem, where this search is very complex. This kind of idiom for searching can be quite useful.

share|improve this answer
Tiny aside: I'd probably refactor the last line into guard (x * y == n); return (x,y) to make it clear that checking the condition holds and supplying the answer are two separate operations. –  Chris Taylor Oct 4 '12 at 7:26
add comment

Another example is constructing all the divisors of a number from its prime factorization (though out of order):

divs n = map product 
           . mapM (\(p,n)-> map (p^) [0..n]) 
           . primeFactorization $ n

-- mapM f = sequence . map f

-- primeFactorization 12  ==>  [(2,2),(3,1)]  -- 12 == 2^2 * 3^1

The function f in mapM f == sequence . map f produces a list of powers of a factor, for each entry in the input list; then sequence forms all paths through the lists picking one number from each at a time; then this list of all possible combinations is fed to map product which calculates the divisors:

12                                      -- primeFactorization:
[(2,2),(3,1)]                           -- map (\(p,n)-> ...):
[ [1,2,4], [1,3] ]                      -- sequence:
[[1,1],[1,3],[2,1],[2,3],[4,1],[4,3]]   -- map product:
[1,3,2,6,4,12]                          --   the divisors of 12

The great description given in sacundim's answer applies here too:

In the context of the list monad, mapM :: (Monad m) => (a -> m b) -> [a] -> m [b] is a nondeterministic list map: a mapping operation that maps a nondeterministic function - such that produces a list of alternative results - over a list, collecting the results nondeterministically, creating a list of all the alternative possible lists of results.

share|improve this answer
add comment

A nice example for list manipulation is querying an HTML/XML document, a la jQuery. jQuery is a monad. Let's examine an example:

$(doc).find('> body')
      .find('> *')
      .find('> caption')

This gives you the captions of all the top-level tables having a CSS class bar. This is an unusual way to use jQuery (usually you'd simply do body > table.bar > caption), but that's because I wanted to show the steps.

In xml-conduit you do it similarly:

child cursor >>= element "body" >>= child
        >>= element "table" >=> attributeIs "class" "bar"
        >>= child >>= element "caption"
        >>= descendants >>= content

What the list monad does is combine the steps. The monad in itself knows nothing about HTML/XML.

In HXT you do it in almost the same way. Newer HXT versions use what are called arrows instead of monads, but the underlying principle is the same.

share|improve this answer
add comment

Monads and list manipulation is even more fun when combined with guard of MonadPlus and perhaps another monad. As an example, let's solve the classic verbal arithmetic puzzle: SEND + MORE = MONEY. Each letter must represent a unique digit and the leading digits can't be zero.

For this, we'll construct a monad stack from StateT and []:

import Control.Monad
import Control.Monad.List
import Control.Monad.State

-- Verbal Arithmetic monad
type VA a = StateT [Int] [] a

The list monads allows us to branch computations to search all possible ways, and the state is the list of digits that are available for choosing. We can run this monad by giving it all possible digits as:

runVA :: VA a -> [a]
runVA k = evalStateT k [0..9]

We'll need one auxiliary function that branches a computation by picking all available digits, and updating the state with what is left:

pick :: VA Int
pick = do
    -- Get available digits:
    digits <- get
    -- Pick one and update the state with what's left.
    (d, ds) <- lift $ split digits
    put ds
    -- Return the picked one.
    return d
    -- List all possible ways how to remove an element from a list.
    split :: [a] -> [(a, [a])]
    split = split' []
    split' _ []      = []
    split' ls (x:rs) = (x, ls ++ rs) : split' (x : ls) rs

Also we'll often need to pick a non-zero digit:

pickNZ :: VA Int
pickNZ = do
    d <- pick
    guard (d /= 0)
    return d

Solving the puzzle is now easy: We can simply implement the addition digit by digit and check using guard that the digits of the result are equal to the sum:

--   SEND
-- + MORE
-- ------
money :: [(Int,Int,Int)]
money = runVA $ do
    d <- pick
    e <- pick
    let (d1, r1) = (d + e) `divMod` 10
    y <- pick
    guard $ y == r1
    n <- pick
    r <- pick
    let (d2, r2) = (n + r + d1) `divMod` 10
    guard $ e == r2
    o <- pick
    let (d3, r3) = (e + o + d2) `divMod` 10
    guard $ n == r3
    s <- pickNZ
    m <- pickNZ -- Actually M must be 1, but let's pretend we don't know it.
    let (d4, r4) = (s + m + d3) `divMod` 10
    guard $ r4 == o
    guard $ d4 == m
    return (ds [s,e,n,d], ds [m,o,r,e], ds [m,o,n,e,y])
    -- Convert a list of digits into a number.
    ds = foldl (\x y -> x * 10 + y) 0

The puzzle has exactly one result: (9567,1085,10652). (Of course the code can be further optimized, but I wanted it to be simple.)

More puzzles can be found here: http://www.primepuzzle.com/leeslatest/alphameticpuzzles.html.

share|improve this answer
add comment

Your Answer


