Alex Rivera | Logout

foldl / foldr query

Asked 2011-05-18T19:58:07.573
11

I'm a beginner at Haskell, and even after reading several explanations of foldr/foldl, I can't understand why I'm getting different results below. What is the explanation?

Prelude> foldl (\_ -> (+1)) 0 [1,2,3]
4
Prelude> foldr (\_ -> (+1)) 0 [1,2,3]
3

Thanks!

Edit
Report

2 Answers

8

That's because the order of the arguments is flipped in foldl. Compare their type signatures:

foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b

So you see, in your code using foldl, you repeatly increment the accumulator, ignoring the list. But in the code with foldr, you don't even touch the accumulator, but just increment the element of the list. As the last element is 3, the result is 3 + 1 = 4.

You could see your misstake more easy, if you'd use a list of characters aka string instead:

ghci> foldr (\_ -> (+1)) 0 ['a','b','c']
3
ghci> foldl (\_ -> (+1)) 0 ['a','b','c']

:1:20:
    No instance for (Num Char)
      arising from the literal `0'
    Possible fix: add an instance declaration for (Num Char)
    In the second argument of `foldl', namely `0'
    In the expression: foldl (\ _ -> (+ 1)) 0 ['a', 'b', 'c']
    In an equation for `it':
        it = foldl (\ _ -> (+ 1)) 0 ['a', 'b', 'c']
ghci>
answered 2011-05-18T20:03:37.240
6

In foldl f, the accumulator is the left argument to f, which you are ignoring, therefore returning 1 + the last element. With foldr, the accumulator is the right argument, so you're increasing the accumulator by 1 for every item, effectively giving the length of the list.

f x y = y + 1

foldl f 0 [1, 2, 3]
= f (f (f 0 1) 2) 3 
= f ignored 3
= 3 + 1
= 4

foldr f 0 [1, 2, 3]
= f 1 (f 2 (f 3 0)))
= f ignored (f ignored (f ignored 0)))
= ((((0 + 1) + 1) + 1)
= 3
answered 2011-05-18T20:02:11.707

Your Answer