How list generators are handled by Haskell? Specifically, why does this
f n = [x:xs | x <- [1..n], xs <- []]
yields empty list? What is xs
in x:xs
in every 'iteration'?
How list generators are handled by Haskell? Specifically, why does this
f n = [x:xs | x <- [1..n], xs <- []]
yields empty list? What is xs
in x:xs
in every 'iteration'?
The zoomed-out answer is that...
[x:xs | x <- [1..n], xs <- []]
... consists of all possible lists generated by picking an element (x
) from [1..n]
plus an element (xs
) from []
and prepending one to the other. Since there are no elements in []
, the number of lists that can be generated in this way is zero.
The zoomed-in answer is that list comprehensions are sugar for the list monad, and so this...
[x:xs | x <- [1..n], xs <- []]
... is equivalent to...
do
x <- [1..n]
xs <- []
return (x:xs)
... that is (after desugaring do-notation)...
[1..n] >>= \x ->
[] >>= \xs ->
return (x:xs)
-- Or, without the line breaks:
[1..n] >>= \x -> [] >>= \xs -> return (x:xs)
... that is (after substituting the definitions of (>>=)
and return
for the list monad):
concatMap (\x -> concatMap (\xs -> [x:xs]) []) [1..n]
concatMap
(which, as the name suggests, is merely map
followed by concat
) on an empty list gives an empty list, and so it becomes...
concatMap (\x -> []) [1..n]
... which amounts to replacing each element of [1..n]
with an empty list and then concat
-ing the result, which produces an empty list.