为什么大多数编程语言对传递给函数的参数使用急切求值?

发布于 2024-12-26 00:51:54 字数 567 浏览 2 评论 0原文

在大多数编程语言中,传递给函数的参数会在函数使用它们之前进行求值,也就是说,它们会立即求值。

对我来说,似乎只有在函数使用参数时(即惰性地)对参数进行求值才更有意义。这对我来说更有意义,因为它似乎会带来性能优势:为什么要评估根本不需要的东西?

此外,假设您想要实现一个 if 函数,该函数接受一个布尔值,以及一个在布尔值为 true 时返回的对象,以及在布尔值为 false 时返回的另一个对象

object if(bool condition, object valueIfTrue, object valueIfFalse) {
  if(condition) return valueIfTrue;
  return valueIfFalse;
}

:参数时,即使函数始终只需要其中一个对象,也始终会计算两个对象,这充其量会产生一些不必要的开销,而最坏的情况会导致无限循环。

也就是说,由于大多数编程语言都使用函数参数的急切求值,我认为通常这样做一定是有原因的。我忽略了热切评估的一些重大好处,是否只是因为以这种方式实现语言更容易,这只是传统,还是什么?

In most programming languages, arguments passed to a function are evaluated before the function uses them, that is, they are evaluated eagerly.

To me, it seems like it would make much more sense to evaluate the arguments only once the function uses them, that is, lazily. This makes more sense to me because it seems like it would have a performance benefit: why evaluate things that are never even needed?

Moreover, suppose you wanted to implement an if function that accepts a boolean, and an object to return if the boolean is true, and another object to return if the boolean is false:

object if(bool condition, object valueIfTrue, object valueIfFalse) {
  if(condition) return valueIfTrue;
  return valueIfFalse;
}

In a language that eagerly evaluates arguments, both objects are always evaluated even though the function will always only need one of them, which, at best, incurs a slight unecessary overhead, and, at worst, causes an infinite loop.

That said, since most programming languages use eager evaluation of function arguments, I assume there must be a reason why it's usually done that way. Is there some big benefit of eager evaluation here that I'm overlooking, is it just because it was easier to implement languages that way, is it just tradition, or what?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

捎一片雪花 2025-01-02 00:51:54

我发现急切评估有几个原因,这两个原因都很重要:

  1. 急切评估意味着副作用会立即且始终发生。如果您使用惰性求值,则不能依赖之前所做的操作的副作用来生效。
  2. 惰性求值会带来一定程度的内存膨胀。存储计算结果通常比存储thunk<所需的内存少得多/a> 描述了计算。这可能导致使用过多的内存(即时间与内存的权衡),有时更重要的是,更难弄清楚程序/算法的内存特征。

惰性求值可以是一个强大的工具,但它并不是没有代价的。纯函数式语言往往会避免问题#1,因为它们(一般来说)没有副作用,但有时仍然会遇到问题#2。允许延迟求值的语言(LISP 宏是其中的一种形式,尽管与延迟求值不同)可以两全其美,但代价是程序员需要付出更多的努力。

There are a couple reasons I've seen for eager evaluation, both of which are important:

  1. Eager evaluation means that side effects happen immediately and always. If you use lazy evaluation, you can't rely on the side effects of something you've done previously to have taken effect.
  2. Lazy evaluation brings with it a certain amount of memory bloat. It generally takes much less memory to store the result of a calculation than it does to store the thunk that describes the calculation. This can lead to using too much memory (ie, time vs. memory tradeoffs) and, sometimes more importantly, a harder time figuring out the memory characteristics of the program/algorithm.

Lazy evaluation can be a powerful tool, but it's not without it's costs. Purely functional languages tend to avoid problem #1 because they don't have side effects (in general), but are still bitten by problem #2 at times. Languages that allow delayed evaluation (LISP macros are a form of this, though not the same as lazy evaluation) can have the best of both worlds, but at the cost of more effort on the programmer's part.

瑾兮 2025-01-02 00:51:54

选项 1 - 将所有参数加载到寄存器中,调用函数

选项 2 - 加载第一个参数,评估是否有必要,等待 CPU 管道清除,获取下一个参数,评估是否有必要...然后将所需参数加载到寄存器中,执行带有额外逻辑的函数来标记哪些寄存器正在使用。

当您等待查看正在执行的代码路径时,“if”已经会导致性能停滞(通过分支预测稍微节省)

Option 1 - load all arguements into registers, call function

Option 2 - load first argument, evaluate if it's necessary, wait for CPU pipeline to clear, get next argument, evaluate if it's necessary .... then load needed paramters into registers, execute function with extra logic to mark which registers are in use.

An 'if' is already going to cause a performance holdup anyway while you wait to see which code path you are executing (slightly saved by branch prediction)

绅士风度i 2025-01-02 00:51:54

为了使惰性求值发挥作用,需要在某处添加额外的代码和数据来跟踪表达式是否已被求值。在某些情况下,这比急切的评估成本更高。确定表达式是否可以从惰性计算中受益可能需要对程序如何工作有非常高水平的了解;编译器和/或解释器当然不会有这种知识。

此外,如果函数或表达式有副作用,则惰性求值策略可能会使程序的行为方式违反直觉且难以调试。这在函数式编程语言中当然不是问题,因为函数式编程语言在设计上就没有副作用。事实上,惰性求值是大多数(如果不是全部)函数式编程语言的默认策略。

话虽如此,没有什么可以阻止您在不同的地方使用这两种策略。如果在重要的程序中使用混合方法,我不会感到惊讶。

In order for lazy evaluation to work there needs to be extra code and data somewhere to keep track of whether an expression has been evaluated. In some cases this would be more costly than eager evaluation. Determining whether an expression can benefit from lazy evaluation may require a very high-level knowledge of how the program works; the compiler and/or interpreter certainly won't have this kind of knowledge.

Also, if the function or expression have side effects, the lazy evaluation strategy might make programs behave in ways that are counterintuitive and hard to debug. This is of course not a problem in functional programming languages where there are no side effects by design. In fact, lazy evaluation is the default strategy for most, if not all, functional programming languages.

That being said, there's nothing that prevents you from using both strategies in different places. I wouldn't be surprised if a hybrid approach is used in non-trivial programs.

一梦等七年七年为一梦 2025-01-02 00:51:54

除了已经提供的出色答案之外,惰性评估还存在另一个实际问题。如果您有一系列表达式,仅在“使用”最后一个表达式时才延迟计算,那么识别性能瓶颈可能会变得相当困难。

Apart from the excellent answers already provided, there's another practical problem with lazy evaluation. If you have a chain of expressions only lazily evaluated when the last one is "used", it can become quite hard to identify performance bottlenecks.

枫以 2025-01-02 00:51:54

早在白垩纪时期,就有许多语言做到了这一点。例如,斯诺博尔。 ALGOL 68 具有“按名称调用”功能,可以实现类似的功能。 C(及其许多派生语言)在一种非常具体的情况下执行此操作,将其描述为“短路”布尔表达式。一般来说,它几乎总是比它的支持能力更多的混乱和错误的来源。

Back in the Cretaceous Period, there were a number of languages that did this. SNOBOL, for example. ALGOL 68 had a "call by name" capability, which did something like this. And C (as well as its many derivatives) does it in one very specific situation, which it describes as "short-circuiting" a boolean expression. In general, it is almost always a source of more confusion and bugs than it is of enabling power.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文