简体   繁体   English

为什么 foldr' 不如 foldl' 严格?

[英]Why is foldr' not as strict as foldl'?

Consider these various attempts at something that works like last :考虑一下这些类似last的各种尝试:

Prelude> import Data.Foldable
Prelude Data.Foldable> foldr const undefined (reverse [1,2,3])
3
Prelude Data.Foldable> foldr' const undefined (reverse [1,2,3])
3
Prelude Data.Foldable> foldl (flip const) undefined [1,2,3]
3
Prelude Data.Foldable> foldl' (flip const) undefined [1,2,3]
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
  undefined, called at <interactive>:5:21 in interactive:Ghci4

It makes sense to me that foldl and foldr both work, since they aren't strict in their accumulator, and it makes sense to me that foldl' doesn't, since it is.对我来说foldlfoldr都可以工作是有道理的,因为它们的累加器并不严格,而对我来说foldl'没有,因为它是有道理的。 But why does foldr' work?但是为什么foldr'工作? Isn't it supposed to be strict in its accumulator too?它的累加器不应该也很严格吗?

For reference, the instance Foldable [] overrides foldr , foldl , foldl' , but not foldr' ( source ):作为参考, Foldable []实例会覆盖foldrfoldlfoldl' ,但不会覆盖 foldr foldr'source ):

instance Foldable [] where
    elem    = List.elem
    foldl   = List.foldl
    foldl'  = List.foldl'
    foldl1  = List.foldl1
    foldr   = List.foldr
    {- ... -}

foldr' is defined by default as ( source ): 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

Note that there is only a strictness annotation on the result of f .请注意, f的结果只有一个严格性注释。 So the initial accumulator is not forced.所以初始累加器不是强制的。

This suggests a different implementation which does force the accumulator:这表明了一个不同的实现,它确实强制累加器:

foldr'' :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldr'' f = foldr (\x z -> f x $! z)

(Edited: the previous version was specialized to lists.) (已编辑:以前的版本专门用于列表。)

I have no idea why one was chosen over the other.我不知道为什么选择一个而不是另一个。 Probably an oversight, and it would be more consistent for foldr' to not use the default implementation in the Foldable [] instance.可能是疏忽, foldr'不使用Foldable []实例中的默认实现会更加一致。


As an aside, the default definition of foldl' is also different from the list one in the same way:顺便说一句, 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM