Previously, Nicolas Rinaudo answered my question on Scala\'s List foldRight Always Using foldLeft?
Studying Haskell currently, my understanding is that foldRig
I can provide an answer for Haskell, but I doubt it will be relevant to Scala:
Let's start with the source for both,
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Now, let's look at where the recursive call to foldl or foldr appears on the right hand side. For foldl, it is outermost. For foldr, it is inside the application of f. This has a couple important implications:
If f
is a data constructor, that data constructor will be left-most, outermost with foldr. This means that foldr implements guarded recursion, such that the following is possible:
> take 5 . foldr (:) [] $ [1..]
[1,2,3,4]
This means that, e.g., foldr can be both a good producer and a good consumer for short-cut fusion. (Yes, foldr (:) []
is an identity morphism for lists.)
This is not possible with foldl because the constructor will be inside the recursive call to foldl and cannot be pattern matched.
Conversely, because the recursive call to foldl is in left-most, outermost position, it will be reduced by lazy evaluation and will not take up space on the pattern-matching stack. Combined with proper strictness annotation (e.g., foldl'
), this allows functions like sum
or length
to run in constant space.
For more on this, see Lazy Evaluation of Haskell.