Removing syntactic sugar: List comprehension in Haskell

List comprehensions (in fact, Monad comprehensions) can be desugared into do notation.

do i <- [1..4]
   j <- [i+1..4]
   return (i,j)

Which can be desugared as usual:

[1..4]   >>= \i ->
[i+1..4] >>= \j ->
return (i,j)

It is well known that a >>= \x -> return b is the same as fmap (\x -> b) a. So an intermediate desugaring step:

[1..4] >>= \i -> 
fmap (\j -> (i,j)) [i+1..4]

For lists, (>>=) = flip concatMap, and fmap = map

(flip concatMap) [1..4] (\i -> map (\j -> (i,j) [i+1..4])

flip simply switches the order of the inputs.

concatMap (\i -> map (\j -> (i,j)) [i+1..4]) [1..4]

And this is how you wind up with Tsuyoshi’s answer.


The second can similarly be desugared into:

concatMap (\i ->
  concatMap (\j ->
    map       (\k ->
      (i,j,k))
    [j+1..6])
  [i+1..6])
[1..6]

Leave a Comment