实际使用`foldl`

时间:2014-09-19 20:42:01

标签: haskell fold foldleft

今天,当我处理一个小脚本时,我使用的是foldl而不是foldl'。我得到了stack overflow,因此我导入了Data.List (foldl')并对此感到满意。这是foldl的默认工作流程。当懒惰版本评估时,只需使用foldl'

Real World Haskell表示在大多数情况下我们应该使用foldl'代替foldlFoldr Foldl Foldl'

  

通常选择在foldrfoldl'之间。

     

...

     

但是,如果组合函数在其第一个参数中是惰性的,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的任何有趣用法都是受欢迎的。

2 个答案:

答案 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