据我所知,渴望评估/应用顺序在应用函数之前评估函数的所有参数,另一方面,惰性评估/正常顺序仅在需要时评估参数。
那么, eager evaluation和applicative order以及lazy evaluation和normal order这对术语有什么区别呢?
谢谢。
据我所知,渴望评估/应用顺序在应用函数之前评估函数的所有参数,另一方面,惰性评估/正常顺序仅在需要时评估参数。
那么, eager evaluation和applicative order以及lazy evaluation和normal order这对术语有什么区别呢?
谢谢。
惰性评估最多评估一个术语一次,而正常顺序将评估它出现的频率。因此,例如,如果您有f(x) = x+x
并且您将其称为f(g(42))
theng(42)
在惰性评估或应用顺序下调用一次,但在正常顺序下调用两次。
渴望评估和应用顺序是同义词,至少在使用计算机程序的结构和解释中的应用顺序定义时,这似乎与您的匹配。(维基百科对应用顺序的定义略有不同,并将其作为急切评估的特例)。
我也在读 SICP,我对作者给出的正常顺序的定义很好奇。对我来说,这似乎与懒惰的评估很相似,所以我去寻找更多关于两者的信息。
我知道这个问题是很久以前提出的,但是我查看了常见问题解答并没有提到回答旧问题,所以我想我会把我找到的东西留在这里,以便其他人将来可以使用它。
这是我发现的,我倾向于同意这些:
我会(和其他人一样)争辩说惰性评估和 NormalOrderEvaluation 是两件不同的事情;上面提到了差异。在惰性求值中,参数的求值被推迟到需要它时,此时参数被求值并且其结果被保存(记忆)。函数中参数的进一步使用使用计算值。C/C++ 运算符 ||、&& 和 ? : 都是惰性求值的例子。(除非某些 C/C++ 新手程序员足够笨重来重载 && 或 ||,在这种情况下,重载版本会按照严格的顺序进行评估;这就是 && 和 || 运算符在 C++ 中永远不应该重载的原因)。
换句话说,每个参数最多被评估一次,可能根本不被评估。
另一方面,NormalOrderEvaluation 会在每次使用表达式时重新计算它。想想 C 宏、支持它的语言中的 CallByName 以及循环控制结构的语义等。正常顺序评估可能比应用顺序评估花费更长的时间,并且可能导致副作用发生不止一次。(这就是为什么在 C/C++ 中通常不应将具有副作用的语句作为宏的参数给出的原因)
如果参数是不变的并且没有副作用,那么两者之间的唯一区别就是性能。实际上,在纯函数式语言中,惰性求值可以被视为对正常顺序求值的优化。由于存在副作用,或者在重新评估时可以返回不同值的表达式,两者具有不同的行为;由于在没有参考透明性的情况下难以推理此类程序,因此正常顺序 eval 在程序语言中的名声尤其不好
还应该注意的是,严格顺序评估(以及惰性评估)可以通过显式备忘录支持正常顺序评估的语言来实现。反之则不然。它需要传入可以调用/消息传递的 thunk、函数或对象,以推迟/重复评估。
和
惰性求值结合了正序求值和共享:
• 在你必须做之前永远不要评估某事(正常顺序)
• 切勿多次评估某事(分享)
来自Kevin Sookocheff的Normal、Applicative 和 Lazy Evaluation帖子(重点是我的风格变化):
懒惰的评价
虽然通过要求对函数参数进行多次评估, 正常顺序评估可能会导致做额外的工作,但应用顺序评估可能会导致程序不会在其正常顺序等效项所在的位置终止。实际上,大多数函数式编程语言使用惰性求值来解决这个问题。
使用惰性求值,我们以一种避免对同一函数进行多次求值的方式延迟函数求值——从而结合了正常顺序求值和应用顺序求值的优点。
使用惰性求值,我们在需要时求值,在求值后,该表达式的所有副本都将更新为新值。实际上,传递给函数的参数存储在内存中的单个位置,因此该参数只需要计算一次。也就是说,我们记住将使用某个参数的所有位置,并且当我们评估一个函数时,我们将参数替换为值。
结果,使用惰性求值,每个参数最多被求值一次。
这太长了,无法在问题下方发表评论,并且用它更新现有答案似乎不合适,因此这个答案。