今天,当我处理一个小脚本时,我使用的是foldl
而不是foldl'
。我得到了stack overflow
,因此我导入了Data.List (foldl')
并对此感到满意。这是foldl
的默认工作流程。当懒惰版本评估时,只需使用foldl'
。
Real World Haskell
表示在大多数情况下我们应该使用foldl'
代替foldl
。 Foldr Foldl Foldl'说
通常选择在
foldr
和foldl'
之间。...
但是,如果组合函数在其第一个参数中是惰性的,
foldl
可能会很高兴地返回foldl'
遇到异常的结果。
一个给定的例子:
(?) :: Int -> Int -> Int
_ ? 0 = 0
x ? y = x*y
list :: [Int]
list = [2, 3, undefined, 5, 0]
okey = foldl (?) 1 list
boom = foldl' (?) 1 list
嗯,我很抱歉,但这是相当学术,有趣但是学术的例子。所以我想问,是否有任何实际使用foldl
的例子?我的意思是,当我们无法用foldl
替换foldl'
时。
P上。 S.我知道,定义术语practical
很难,但我希望你能理解我的意思。
P上。 P. S.我明白,为什么lazy foldl
在haskell中是默认的。我不要求任何人移动山并默认严格版本。我对foldl
函数的独占使用示例非常感兴趣:)
P上。 P. P. S.嗯,foldl
的任何有趣用法都是受欢迎的。
答案 0 :(得分:12)
这是一个更实际的例子,使用经典的天真Fibonacci实现来模拟昂贵的计算:
fib :: Int -> Int
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
f :: Int -> Int -> Int
f a b = if b < 1000 then b else min b a
然后,如果你有
> -- Turn on statistics for illustrative purposes
> :set +s
> foldl f maxBound $ map fib [30, 20, 15]
987
(0.02 secs, 0 bytes)
> foldl' f maxBound $ map fib [30, 20, 15]
987
(4.54 secs, 409778880 bytes)
这里我们在懒惰版本和严格版本之间的运行时性能方面存在巨大差异,懒惰版本因山体滑坡而获胜。当然,您的电脑数量可能因电脑而异,但您肯定会注意到执行速度的差异。 foldl'
强制每次计算发生,而foldl
则不会。这对于像
> foldl f maxBound $ map length [repeat 1, repeat 1, replicate 10 1]
10
与fib
示例不同,此计算在技术上涉及底部,因为length $ repeat 1
永远不会完成其计算。如果没有f
的两个参数都是严格的(如foldl'
所做的那样),那么我们实际上有一个程序会停止,而不会停止。
答案 1 :(得分:5)
我可以想到一个(虽然它可能只会通过优化编译器产生良好的代码):
last = foldl (\_ x -> x) (error "emptyList")
foldl'
:
> foldl (\_ x -> x) (error "emptyList") [error "foo", "last"]
"last"
> foldl' (\_ x -> x) (error "emptyList") [error "foo", "last"]
"*** Exception: foo