Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

foldl / foldr query

Tags:

haskell

fold

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!

like image 562
Frank Avatar asked May 18 '11 19:05

Frank


People also ask

What is the difference between foldr and foldl?

Difference Between foldl and foldr The difference is that foldl is tail-recursive, whereas foldr is not. With foldr and non-optimized patterns, proc is applied to the current value and the result of recursing on the rest of the list. That is, evaluation cannot complete until the entire list has been traversed.

Is foldl or foldr better?

Only foldr is lazy and can be used for codata/infinite streams. While foldl is tail-recursive (enhanced with strict application foldl' can avoid stack overflow). This is why foldr should be used by default in Haskellin order preserve laziness across function composition.

How does foldr work on infinite lists?

But foldr applies the function to a value in the list ( f x ) before it calls itself to recurse further. That means that if you have a function that can return a final result after one application, you could stop evaluating the infinite list there.

What does foldr return?

foldr takes two arguments: A combining function and an identity value. It then returns a function that takes a list and returns an accumulated value. In this case, a -> b -> b is still the combining function and b is the identity value.


2 Answers

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>
like image 66
fuz Avatar answered Oct 02 '22 13:10

fuz


In the foldl case, the lambda is being passed the accumulator as the first argument, and the list element as the second. In the foldr case, the lambda is being passed the list element as the first argument, and the accumulator as the second.

Your lambda ignores the first argument, and adds 1 to the second, so in the foldl case you are adding 1 to the last element, and in the foldr case, you are counting the number of elements in the list.

like image 36
pat Avatar answered Oct 02 '22 13:10

pat