Home > Blockchain >  Haskell - Unexpected result from nested generator in list comprehension
Haskell - Unexpected result from nested generator in list comprehension

Time:10-11

In this expression, x is supposed to be 1 unit larger than n. However, the resulting list is made of mostly negative numbers.

f :: [Integer]
f = [x-n | x <- [1,2..], n <- [0,1..]]

Output from take 10 f:

[1,0,-1,-2,-3,-4,-5,-6,-7,-8]

I expected it to be a list of 1s and I am not sure why that is not the case.

Thanks.

CodePudding user response:

In your definition, for each value of x every value of n is paired with it. For example consider

g :: [Integer]
g = [ (x, n) | x <- [1,2..4], n <- [0,1..3]]

The output is

[(1,0),(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(2,3),(3,0),(3,1),(3,2),(3,3),(4,0),(4,1),(4,2),(4,3)]

If you wanted the elements of x and n to be paired off by their respective positions then try zip:

f1 = [x-n | (x, n) <- zip [1,2..] [0,1..]]
> take 10 f1
[1,1,1,1,1,1,1,1,1,1]

CodePudding user response:

As @Willem Van Onsen mentions in the comments, your comprehension amounts to a nested loop, where the outer loop on x never moves to the next iteration. What you are seeing is thus (1 - n) for each value of n.

What you seem to need is to zip the two lists together, and then do your subtraction, like so:

f = map (\x -> (fst x) - snd x) $ zip [1,2..] [0,1..]

This will take the elements from each list pairwise and do the subtraction to give an answer of 1 as you expect.

CodePudding user response:

The code you give

f :: [Integer]
f = [x-n | x <- [1,2..], n <- [0,1..]]

is the imperative equivalent to

for x in range(1, inf):
    for n in range(0, inf):
        return x - n

so clearly, x is 1 at first, then it loops for n all the way up to infinity. So you get 1 - 0, 1 - 1, 1 - 2, etc...

From your question I guess you want to pair elements from each list one by one instead of a nested loop. Hence, the code should be

zipWith (-) [1..] [0..] -- this is equal to the infinite list [1,1,1,1,...]
  • Related