Search code examples
haskellfunctional-programmingfoldbinary-operatorsassociativity

Understanding Folds in Haskell


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?


Solution

  • 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