foldl如何懒惰?
在Haskell中有关于foldl
, foldr
和foldl'
很多很好的问题和答案。
所以现在我知道:
1) foldl
是懒惰的
2)不要使用foldl
因为它会炸毁堆栈
3)用foldl'
来代替,因为它是严格的(ish)
如何评估foldl
:
1)创建了一大堆thunk
2)在Haskell创建thunk之后,thunk被减少
3)如果太多的thunk,堆溢出
我感到困惑的是:
1)为什么减少必须发生在所有thunk-ing之后?
2)为什么不foldl
评估就像foldl'
? 这只是一个实现的副作用?
3)根据定义, foldl
看起来可以使用尾递归有效地进行评估 - 我如何判断一个函数是否会被有效地评估? 看起来我不得不开始担心Haskell的评估顺序,如果我不想让我的程序崩溃的话。
提前致谢。 我不知道我对foldl
评估的理解是否正确 - 如有必要请提出更正建议。
更新:它看起来对我的问题的答案与正常形式,弱正常形式和正常形式,以及哈斯克尔的执行情况有关。
然而,我仍然在寻找一个例子,更为热切地评估组合函数会导致不同的结果(崩溃或不必要的评估)。
你知道,按照定义:
foldl op start (x1:x2:...:xN:[]) = ((start `op` x1) `op` x2) ...
foldl中这样做的行是:
foldl op a (x:xs) = foldl op (a `op` x) xs
你是对的,这是尾递归,但观察表达式
(a `op` x)
是懒惰的,在列表的最后,一个巨大的表达将会被构建,然后被减少。 foldl'的不同之处在于上面的表达式被迫在每次递归中进行评估,所以最终你在弱头标准形式下获得了一个值。
简短的回答是,在foldl f
,它不一定,此案f
是严格的,所以它可能是太急于减少的thunk前面。 但是,实际上它通常是,所以你几乎总是想要使用foldl'
。
我写了关于foldl
和foldl'
的评估顺序如何在另一个问题上工作的更深入的解释。 这很长,但我认为它应该为你澄清一些事情。
我仍然在寻找一个更加热切地评估组合函数会导致不同结果的例子
一般的经验法则永远不会使用foldl
。 总是使用foldl'
, 除非你使用foldr
。 我认为你对foldl
了解得很多,理解为什么应该避免。
另请参见:真实世界Haskell>函数式编程#左折叠,懒惰和空间泄漏
但是,你的问题忽略了foldr
。 关于foldr
处在于它可以产生增量结果,而foldl'
需要在得到答案之前遍历整个列表。 这意味着foldr
的懒惰允许它与无限列表一起工作。 还有关于这类事情的详细问题和答案。
介绍完这些后,让我试着简洁地回答你的问题。
1)为什么减少必须发生在所有thunk-ing之后?
减少只发生在严格点。 例如,执行IO是一个严格点。 foldl'
使用seq
来添加foldl
没有的额外严格点。
2)为什么不像foldl'那样评估foldl? 这只是一个实现的副作用?
由于foldl'
中的额外严格点,
3)根据定义,foldl对我来说看起来像是一个尾递归函数 - 我如何判断一个函数是否会被有效地评估? 看起来我不得不开始担心Haskell的评估顺序,如果我不想让我的程序崩溃的话。
您需要更多地了解懒惰评估。 懒惰评估并不是Haskell独有的,但Haskell是默认为懒惰的极少数语言之一。 对于初学者,只记得总是使用foldl'
,你应该没问题。
如果有一天懒惰真的让你陷入麻烦,那么你应该确保你明白懒惰和Haskell的严格要求。 你可能会说,理论日是懒惰学习的严格要求。
另见:PLAI>第三部分:懒惰
链接地址: http://www.djcxy.com/p/42973.html上一篇: How is foldl lazy?