Reputation: 14346
The Foldr Foldl Foldl' wiki page describes the differences between foldr
and foldl
. Both process lists from left-to-right, but foldr
accumulates the result from right-to-left whereas foldl
does so from left-to-right.
The page goes on to discourage the use of foldl
in favor of the eager version foldl'
, which is more efficient.
Is there a corresponding eager version of foldr
, presumably called foldr'
? If so, is there a reason that it isn't mentioned on the wiki page?
Upvotes: 4
Views: 211
Reputation: 51109
A quick Hoogle search shows that there is, indeed, a foldr'
defined in Data.Foldable
.
I assume the reason it isn't mentioned on the linked page is that it isn't relevant to the problem of stack overflows discussed there. When calculating a sum using foldr (+) 0
on a large list, the stack overflow that may occur isn't a result of lazy application of the operator (+)
. Rather, it occurs because a fundamental feature of a right fold (whether strict or lazy) is that the most deeply nested application of the operator occurs at the end of the list. For an operator like (+)
that requires evaluation of both operands to yield any sort of result, this means that either foldr
or foldr'
must build up an O(n) stack of continuations before getting to the end of the list where the (+)
operator can start to do "real work".
Upvotes: 4
Reputation: 48611
Both foldr
and foldl'
are extremely useful for lists. Neither foldl
nor foldr'
is often useful for lists. But these days, those functions are actually methods of the Foldable
class, and they are useful for some instances. To take an extreme example, consider snoc lists:
data SL a = SL a :> a | Nil
infixl 5 :>
instance Foldable SL where
foldMap _ Nil = mempty
foldMap f (xs :> x) = foldMap f xs <> f x
foldl _ b Nil = b
foldl f b (xs :> x) = f (foldl f b xs) x
foldr' _ n Nil = n
foldr' c n (xs :> x) =
let n' = c x n
in n' `seq` foldr' c n' xs
For snoc lists, foldl
and foldr'
are really useful, while foldr
and foldl'
are pretty much useless!
Many Foldable
containers can make good use of all four of these methods. For example, Data.Set.Set
, Data.Map.Map k
and Data.Sequence.Seq
can each be folded perfectly well in either direction.
import Data.Sequence (Seq)
import qualified Data.Sequence as S
toForwardList :: Seq a -> [a]
toForwardList = foldr (:) []
toReverseList :: Seq a -> [a]
toReverseList = foldl (flip (:)) []
The forward and reverse conversions are equally efficient and equally lazy.
Upvotes: 0
Reputation: 116174
There's no need for foldr'
, sonce one can always use foldr f
with a strict f
to achieve the same goal.
We could define it...
foldr' f a xs = foldr f' a xs
where f' x y = seq x (seq y (f x y))
... but it's simpler to pass a strict f
at the call point instead, if needed.
Upvotes: 9