From what I understand about folds in Haskell, foldl (-) 0 [1..5] gives a result of -15 by calculating 0-1-2-3-4-5, and foldr (-) 0 [1..5] gives a result of -5 by calculating 5-4-3-2-1-0. Why is it then that both foldl (++) "" ["a", "b", "c"] and foldr (++) "" ["a", "b", "c"] give a result of "abc", and the result of foldr is not, instead, "cba"?
Is there something I'm missing in understanding the differences between foldl and foldr?
I think this part from the docs makes it clearer:
In the case of lists, foldr, when applied to a binary operator, a starting value (typically the right-identity of the operator), and a list, reduces the list using the binary operator, from right to left:
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...). . .
In the case of lists, foldl, when applied to a binary operator, a starting value (typically the left-identity of the operator), and a list, reduces the list using the binary operator, from left to right:
foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
If you look at the example breakdown, the concatenation foldr is equivalent to:
"a" ++ ("b" ++ ("c" ++ ""))
And for foldl, it would be equivalent to:
(("" ++ "a") ++ "b") ++ "c"
For string concatenation, these are the same.
For subtraction however,
1 - (2 - (3 - 0))
Gives a different result than:
((0 - 1) - 2) - 3
Actually foldr (-) 0 [1..5] equals 3, because it's:
(1 - (2 - (3 - (4 - (5 - 0))))
The answer to this question is in the type of foldr function:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
As we see, (a -> b -> b) function has iterated element as the first argument and accumulator as the second one. That's why with foldr (++) "" ["a", "b", "c"] we have:
("a" ++ ("b" ++ ("c" ++ "")))
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