关注< Real World Haskell> ,据说foldl'
是foldl
的严格版本。
但我很难理解,strict
意味着什么?
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
foldl' f z0 xs0 = lgo z0 xs0
where lgo z [] = z
lgo z (x:xs) = let z' = f z x in z' `seq` lgo z' xs
答案 0 :(得分:12)
它并不广为人知,但foldl'
在累加器参数中实际上是非严格的!回想一下类型:
foldl' :: (a -> b -> a) -> a -> [b] -> a
它在参数2中的严格程度取决于为参数1给出的函数的严格性,因为你看是否通过了const
:
Prelude Data.List> foldl' (const (+1)) undefined [1]
2
Prelude Data.List> foldl' (const (+1)) undefined [1..4]
5
你会天真地想,“foldl'是严格的”意味着“累加器参数中的严格”。上述内容与此相矛盾。
然而,它更加阴险,因为严格性仅仅是在循环的cons情况下函数应用的结果。如果你输入基础案例,你仍然会得到底部,但不是诱导案例:
Prelude Data.List> foldl' (const (+1)) undefined []
*** Exception: Prelude.undefined
严格性in argument 2 也取决于参数3的值!
这就是我写它的方式:第二个论点中的“完全”严格。
foldl' f z0 xs0 = go z0 xs0
where
go !z [] = z
go !z (x:xs) = go (f z x) xs
在第二个论点中,这是真正严格的,你可以看到:
Prelude Data.List.Stream> foldl' (\a b -> 1) undefined [undefined]
*** Exception: Prelude.undefined
与Haskell2010版本相比:
Prelude Data.List.Stream> Data.List.foldl' (\a b -> 1 ) undefined [undefined]
1
此实际具有实际影响 - 当前定义不会一致地取消其累加器参数。
历史记录:当我们在2007年为流融合论文指定列表库的严格语义时发现了这一点,并且在Duncan Coutt的PhD thesis中给出了指定严格性的方法。
答案 1 :(得分:6)
foldl和(严格)foldl'接近于语义上的等价物。不同之处在于性能,尤其是在横切大型列表时。懒惰有建立一个thunk和foldl'的开销是更有效的方式来达到这个结果,因为它不会构建一个巨大的thunk。
有一篇非常好的文章详细解释了Haskell Wiki
严格的函数就像C语言或其他语言中的函数一样,因为它们的参数通常都是热切评估的。
答案 2 :(得分:0)
严格函数是一个函数,其参数在正文之前进行求值。