Для справки: экземпляр Foldable []
переопределяет foldr
, foldl
, foldl'
, но не foldr'
( источник ):
instance Foldable [] where
elem = List.elem
foldl = List.foldl
foldl' = List.foldl'
foldl1 = List.foldl1
foldr = List.foldr
{- ... -}
foldr'
по умолчанию определяется как ( source ):
foldr' :: (a -> b -> b) -> b -> t a -> b
foldr' f z0 xs = foldl f' id xs z0
where f' k x z = k $! f x z
Обратите внимание, что есть только аннотация строгости к результату f
. Таким образом, начальный аккумулятор не принудительно.
Это предлагает другую реализацию, которая заставляет аккумулятор:
foldr'' :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldr'' f = foldr (\x z -> f x $! z)
(Отредактировано: предыдущая версия была специализирована для списков.)
Понятия не имею, почему одно было предпочтено другому. Вероятно, это недосмотр, и для foldr'
было бы более логично не использовать реализацию по умолчанию в экземпляре Foldable []
.
Кроме того, определение по умолчанию foldl'
также отличается от указанного в списке таким же образом:
-- Default (class Foldable t where ...)
foldl' :: (b -> a -> b) -> b -> t a -> b
foldl' f z0 xs = foldr f' id xs z0
where f' x k z = k $! f z x
-- List implementation
foldl' :: forall a b . (b -> a -> b) -> b -> [a] -> b
foldl' k z0 xs =
foldr (\(v::a) (fn::b->b) -> oneShot (\(z::b) -> z `seq` fn (k z v))) (id :: b -> b) xs z0