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!
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.
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.
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.
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.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With