Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell “foldl”的实际使用`_Haskell_Fold_Foldleft - Fatal编程技术网

Haskell “foldl”的实际使用`

Haskell “foldl”的实际使用`,haskell,fold,foldleft,Haskell,Fold,Foldleft,今天,当我在编写一个小脚本时,我使用了foldl而不是foldl'。我得到了堆栈溢出,所以我导入了Data.List(foldl'),并对此感到满意。这是我使用foldl的默认工作流。当惰性版本需要评估时,只需使用foldl' Real World Haskell说,在大多数情况下,我们应该使用foldl'而不是foldl。说 通常在foldr和foldl'之间进行选择 但是,如果组合函数在其第一个参数中是惰性的,foldl可能会愉快地返回一个结果,其中foldl'遇到异常 举个例子: (?)

今天,当我在编写一个小脚本时,我使用了
foldl
而不是
foldl'
。我得到了
堆栈溢出
,所以我导入了
Data.List(foldl')
,并对此感到满意。这是我使用
foldl
的默认工作流。当惰性版本需要评估时,只需使用
foldl'

Real World Haskell
说,在大多数情况下,我们应该使用
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.p.S.我理解,为什么haskell默认使用lazy
foldl
。我不要求任何人移动这座山,并将严格版本作为默认版本。我只是对独家使用
foldl
函数的示例非常感兴趣:)

p.p.p.S.好吧,欢迎大家使用
foldl

我可以想到一个(尽管这可能是只有通过优化编译器才能产生好的代码):

它在
foldl'
中没有正确的行为:

> foldl (\_ x -> x) (error "emptyList") [error "foo", "last"]
"last"
> foldl' (\_ x -> x) (error "emptyList") [error "foo", "last"]
"*** Exception: foo

下面是一个更实际的示例,使用经典的naive 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
在这里,懒惰版本和严格版本在运行时性能上有着巨大的差异,懒惰版本以压倒性优势胜出。当然,您的数字可能因计算机而异,但您肯定会注意到执行速度的不同。
foldl'
强制执行每个计算,而
foldl
则不执行。这在以下方面也很有用

> foldl f maxBound $ map length [repeat 1, repeat 1, replicate 10 1]
10

fib
示例不同,此计算技术上涉及底部,因为
length$repeat 1
永远不会完成其计算。通过使
f
的两个参数都不严格(正如
foldl'
所做的那样),我们实际上有了一个停止的程序,而不是一个永远不会停止的程序。

除了避免
未定义的
,您还可以使用
foldl
来避免潜在的昂贵操作。如果折叠函数在成功操作的早期退出,则可以避免由于懒惰而执行昂贵的计算。可能有更清晰的方法来编写它(我想到了monoids),但是折叠可以很好地用于编译器优化。但是无法想象这样一个函数的好例子。好吧,这看起来真的像
?0=0
。但无论如何,谢谢你再举一个例子。你用
reverse
再加上
foldr
不是更好吗?这样,您也不必处理整个列表。@托梅利斯我不是说这是最好的方法,只是这是一个例子,说明了foldl是一个更好的选择。好吧,谢谢您的回答。现在我有一些使用
foldl
的有趣例子:D@TomEllis
reverse
处理整个列表。@JeremyList这是真的。我不记得我在想什么了!
> -- 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 f maxBound $ map length [repeat 1, repeat 1, replicate 10 1]
10