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?
