渴望评估/应用顺序和惰性评估/正常顺序

Posted

技术标签:

【中文标题】渴望评估/应用顺序和惰性评估/正常顺序【英文标题】:Eager evaluation/applicative order and lazy evaluation/normal order 【发布时间】:2011-06-05 19:02:52 【问题描述】:

据我所知,急切求值/应用顺序会在应用函数之前对函数的所有参数求值,另一方面,惰性求值/正常顺序仅在需要时才求值。

那么,eager evaluationapplicative order 以及 lazy evaluationnormal order 这对术语有什么区别

谢谢。

【问题讨论】:

【参考方案1】:

懒惰的评估最多评估一个术语一次,而正常顺序将评估它出现的频率。因此,例如,如果您有 f(x) = x+x 并将其称为 f(g(42)),那么 g(42) 在惰性求值或应用顺序下被调用一次,但在正常顺序下被调用两次。

渴望评估和应用顺序是同义词,至少在使用计算机程序的结构和解释中的应用顺序定义时,这似乎与您的匹配。 (Wikipedia 对应用顺序的定义略有不同,并将其作为急切求值的特例)。

【讨论】:

是的,我正在阅读 SICP。我按照 Wikipedia 链接在 Lazy evaluation 中找到了这个:“表达式永远不会被多次评估,称为应用顺序评估。”这意味着应用顺序也可以用作惰性评估的子类型?我有点困惑。 @Ryan:显然,“惰性评估”页面使用的应用顺序定义与“评估策略”页面不同。我认为在这种情况下,最好忽略***并按照 SICP 所说的去做。 不幸的是,***的文章对这些概念非常混乱。据我所知,这个答案或多或少是正确的。我会稍微指出,“应用顺序”是指急切评估策略使用的评估顺序(按值调用/按引用调用),而“正常顺序”是指惰性评估策略使用的评估顺序(按名称调用/根据需要调用)。不过,这可能只是我的特殊解释。结论:如果您曾经在书面上使用过这些词,请明确定义它们! :)【参考方案2】:

我也在读 SICP,我一直对作者给出的正常顺序的定义感到好奇。对我来说,这似乎与惰性评估很相似,所以我去寻找有关两者的更多信息。

我知道这个问题是很久以前提出的,但我查看了常见问题解答并发现没有提及回答旧问题,所以我想我会把我找到的内容留在这里,以便其他人可以在未来。

这是我发现的,我倾向于同意这些:

我会(和其他人一样)认为懒惰的评估和 NormalOrderEvaluation 是两个不同的东西;不同的是 上面提到的。在惰性求值中,参数的求值是 推迟到需要它,此时参数被评估 并将其结果保存(记忆)。论点的进一步使用 函数使用计算值。 C/C++ 运算符 ||、&& 和 ? : 都是惰性求值的例子。 (除非一些新手 C/C++ 程序员很笨,可以重载 && 或 ||,在这种情况下 重载版本按照严格的顺序进行评估;这就是为什么 && 和 ||运算符在 C++ 中永远不应该被重载)。

换句话说,每个参数最多被评估一次,可能不会 完全没有。

另一方面,NormalOrderEvaluation 重新计算表达式 每次使用它。想想 C 宏,CallByName 在语言中 支持它,以及循环控制结构的语义等。 正常顺序评估可能需要比应用顺序更长的时间 评估,并且可能导致副作用发生不止一次。 (这就是为什么,当然,带有副作用的陈述通常应该 不能作为 C/C++ 中宏的参数)

如果参数是不变的并且没有副作用,那么唯一的 两者的区别在于性能。的确,在纯粹 函数式语言,惰性求值可以看成是一种优化 正态评价。存在副作用或表达式 重新评估时可以返回不同的值,两者具有 不同的行为;正常顺序 eval 尤其有坏处 由于推理困难而在程序语言中享有盛誉 关于没有参照透明的此类程序

还应注意,严格顺序评估(以及惰性 评估)可以用支持正常顺序的语言来实现 通过显式备忘录进行评估。反之则不然。这个需要 传入可以调用/消息传递的 thunk、函数或对象 为了推迟/重复评估。

惰性求值结合了正序求值和共享:

• 除非必须(正常顺序),否则永远不要评估某事

• 切勿多次评估某事(分享)

http://c2.com/cgi/wiki?LazyEvaluation

http://cs.anu.edu.au/student/comp3610/lectures/Lazy.pdf

【讨论】:

"还应注意,通过显式备忘录支持正常顺序评估的语言可以实现严格顺序评估(以及惰性评估)。"我不认为那部分是真的。如果该语言仅支持正常顺序评估,那么您如何明确地备注任何内容?您需要某种机制来引入严格性,无论是严格的变量定义还是类似 Haskell 的 seq 运算符,它强制其左操作数在右操作数之前被评估。【参考方案3】:

来自Kevin Sookocheff 的Normal, Applicative and Lazy Evaluation 帖子(重点,风格改变了我的):

懒惰评估

虽然正常顺序评估可能会导致做额外的工作 要求对函数参数进行多次评估, 应用顺序评估可能会导致程序不 在它们的正常顺序等价物所在的地方终止。在实践中,大多数 函数式编程语言使用 lazy 解决了这个问题 评价

通过惰性求值,我们可以延迟函数求值,从而避免 对同一函数的多次评估——因此结合了 正常顺序应用顺序评估的好处。

懒惰 评估,我们在需要时评估一个值,然后 评估该表达式的所有副本都更新为新的 价值。实际上,传递给函数的参数存储在 内存中的单个位置,因此只需要评估参数 一次。也就是说,我们记住了我们确定的所有位置 参数将被使用,当我们评估一个函数时,我们替换 与价值的论据。

因此,惰性评估每 参数最多评估一次

这太长了,无法在问题下方发表评论,并且用它更新现有答案似乎不合适,因此这个答案。

【讨论】:

以上是关于渴望评估/应用顺序和惰性评估/正常顺序的主要内容,如果未能解决你的问题,请参考以下文章

链式静态函数调用之间的参数评估顺序

短路评估顺序和前缀增量运算符

&= 和 |= 是不是有定义的评估顺序?

排序点和评估顺序

评估布尔语句的顺序是啥? [复制]

记住C中运算符的评估顺序和优先级的快捷方式[重复]