0

Here an example to illustrate what I mean

Prelude> foldr (-) 0 [0,1]  
-1

I thought here it would basically do 0 - 0 = 0; 1 - 0 = 1; but the actual result is -1

I tried it with other examples

Prelude> foldr (-) 1 [1,3]   
-1

Prelude> foldr (-) 1 [1,9]
-7

I probably misunderstood how foldr works so I would be happy about an explanation :)

alias
  • 28,120
  • 2
  • 23
  • 40
SpringArt
  • 25
  • 4
  • See also [foldl versus foldr](https://stackoverflow.com/q/3082324/791604), [List folds as structural transformations](https://wiki.haskell.org/Fold#List_folds_as_structural_transformations). – Daniel Wagner Dec 09 '21 at 17:28

3 Answers3

4

Consider the following function:

printfoldr f init xs = foldr (\el acc -> "(" ++ el ++ f ++ acc ++ ")") (show init) $ map show xs

This function simulates how the foldr function expands and outputs its string representation.

Let's run a few tests:

λ> printfoldr "-" 0 [1,2,3,4]
"(1-(2-(3-(4-0))))"

-- the test cases you provided
λ> printfoldr "-" 0 [1,2]
"(1-(2-0))" -- This reduces to -1 which is the result you had

λ> printfoldr "-" 1 [1,3]
"(1-(3-1))" -- This reduces to -1 which is also the result you had

λ> printfoldr "-" 1 [1,9]
"(1-(9-1))" -- reduces -7 which is also correct

So in general, foldr with type foldr :: (a -> b -> b) -> b -> t a -> b works as follows:

x0 `f` (x1 `f` ...(xn-2 `f` (xn-1 `f` (xn `f` init))))

where f is of type (a -> b -> b), x is of type a and init is of type b.

user1984
  • 5,990
  • 2
  • 13
  • 32
3

Try foldr (-) 0 [1, 2, 3, 4, 5]. You should get 3. That's because the fold is equivalent to (1 - (2 - (3 - (4 - (5 - 0))))) -- it's starting from the right. If you try foldl, you should get -15. That's because it's starting from the left and is equivalent to (((((0 - 1) - 2) - 3) - 4) - 5).

Your shorter example, foldr (-) 0 [0, 1], is equivalent to 0 - (1 - 0), which reduces to -1.

asthasr
  • 9,125
  • 1
  • 29
  • 43
2

foldr is defined as follows:

foldr f b [] = b
foldr f b (x:xs) = f x (foldr f b xs)

You recursively fold the tail of the list, then apply f to the head and the recursive result. Note that the base value is used at the end of the sequence, not the beginning.

Thinking of it as simply applying the function to one value after another only works if f is associative. For example, 1 + (2 + (3 + 0)) == ((1+2) + 3) + 0.

Subtraction, though, is not associative. In general, x - y - z is only equal to (x - y) - z, not x - (y - z).

chepner
  • 497,756
  • 71
  • 530
  • 681