Can I unsugar list comprehension in this expression:
[(i,j) | i <- [1..4], j <- [i+1..4]]
This is the output:
[(1,2),
concatMap (\i -> map (\j -> (i, j)) [i+1 .. 4]) [1 .. 4]
There is yet another translation scheme, it is due to Wadler, as far as I know.
This would give:
let
lc_outer (x:xs) = let lc_inner (y:ys) = (x,y) : lc_inner ys
lc_inner [] = lc_outer xs
in lc_inner [x+1.. 4]
lc_outer [] = []
in lc_outer [1..4]
This translation avoids needless construction of singleton lists in the innermost level that would need to get flattened with concatMap later.
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]
The desugared code is:
concatMap (\i -> concatMap (\j -> (i, j) : []) [i+1..4]) [1..4]
Which can be refactored to Tsuyoshi Ito's answer.