按需要呼叫与按名称呼叫
我不明白按名称呼叫和按需要呼叫之间的区别。据我了解,按需调用方法恢复返回的答案。但它如何帮助我们,结果之间有什么根本区别吗?
例如,
begin integer n;
procedure foo(e, n);
integer e, n;
begin
for n := 1 step 1 until 10 do begin
prints(`;;; the value of e is ');
printnln(e)
end
end;
foo(2 * n, n)
end
所以在按名称调用中,据我了解,我们将得到:
;;; the value of e is 2
;;; the value of e is 4
;;; the value of e is 8
等等。这是因为我们将 2*n
传递给 e
,而 e
每次都会用新的 i
进行计算。 按需调用会发生什么?
I didn't understand the diffrence between Call-by-name and Call-by-need. As I understood, Call-by-need method restores the answer returned. But how It helps us, and Is there any fundamental difference between the results ?
For example,
begin integer n;
procedure foo(e, n);
integer e, n;
begin
for n := 1 step 1 until 10 do begin
prints(`;;; the value of e is ');
printnln(e)
end
end;
foo(2 * n, n)
end
So in call-by-name, as I understood, We will get:
;;; the value of e is 2
;;; the value of e is 4
;;; the value of e is 8
and so on. This is because we pass 2*n
to e
, and e
is evaluate with the new i
everytime.
What would happen in call-by-need?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
看来您的困惑源于您在 命令 上下文中思考这一事实。 按需要调用与按值调用的讨论主要涉及声明性语言和函数式语言以及 lambda 演算。
您可以在这篇关于评估策略的文章中看到,按名称调用和按需调用被认为是惰性评估策略。延迟求值是指当表达式作为参数传递给函数时,在进入函数体之前不会对其求值,而是仅在函数内第一次访问/读取它时才求值。如果此类表达式的结果从未在内部使用过,则永远不会对其求值。
例如<代码>? : 运算符在 Java 中是惰性的,如下面的代码所示:
按需调用是大多数具有纯子集的函数式语言的基本功能。在纯函数式语言中,每个函数都必须参照透明,即他们不能有副作用。这样的纯函数具有这样的属性:对于某些给定的输入,它们总是返回相同的输出,无论如何多次打电话,他们从来没有改变“世界状况”的任何事情。它们的行为就像写在纸上的数学函数一样。
正如您已经意识到的,在调用非纯函数时,按需调用策略是不可行的,因为您很可能对连续调用产生的副作用感兴趣。另一方面,当在纯函数式语言中使用时,它成为性能的一个重要特征(参见下面的第二个示例)。另外,请参阅有关 图缩减 和 记忆。
现实世界的示例
第一。使用图形缩减的常用系统的一个示例是阿帕奇蚂蚁。 Ant 不会对目标求值两次。这种设计可以方便地草拟声明性构建计划。
第二。如果您想查看记忆化的良好演示,请输入此Haskell 代码到 GHC 解释器看看会发生什么:
注意。您可能还听说过按值调用评估策略。与按名称调用和按需要调用相比,按值调用是一种严格的评估策略。它就像按名称调用,多次调用会导致多次评估。对于习惯 C# 或 Java 等命令式语言的程序员来说,这是最常见的范例。
It seems that your confusion stems from the fact that you are thinking in an imperative context. The discussion of call-by-need vs. call-by-value mostly comes up about declarative and functional languages, and lambda calculus.
You can see in this article about evaluation strategies that both call-by-name and call-by-need are considered lazy evaluation strategies. Lazy evaluation means that when an expression is passed as a parameter to a function, it is not evaluated before entering the function body, but only when it is accessed/read the first time inside the function. If the result of such expression is never used inside, then it will never be evaluated.
For example the
? :
operator is lazy in Java as the below code demonstrates:Call-by-need is an essential feature of most functional languages which have a pure subset. In a purely functional language, every function has to be referentially transparent, i.e. they cannot have side-effects. Such pure functions have the property that for some given input they always return the same output, no matter how many times called, and that they never change anything in the "state of the world". They behave just like mathematical functions written on the paper.
As you have already realized, call-by-need strategy is not feasible when calling non-pure functions, because you are most probably interested in the side-effects due to the consecutive calls. On the other hand it becomes an essential feature for performance when used in purely functional languages (see the second example below). Also, see these wiki pages about the concepts of Graph Reduction and Memoization.
Real-world examples
First. One example of a commonly used system which uses graph reduction is Apache Ant. Ant does not evaluate a target twice. This design makes it convenient to sketch up a declarative build plan.
Second. If you want to see a good demonstration of memoization, type this Haskell code to a GHC interpreter and see what happens:
Note. You might also have heard about the call-by-value evaluation strategy. In contrast with call-by-name and call-by-need, call-by-value is a strict evaluation strategy. It is like call-by-name in the sense that calling multiple times result in multiple evaluation. This is the most common paradigm for programmers who are accustomed to imperative languages like C# or Java.
按名称调用是一种函数调用规则,其中当调用接收函数 foo 时,不是评估 foo 的参数,而是 foo 接收(在幕后)一个适当的对象,该对象将允许它评估它的参数需要;或者等效地,评估通过宏替换进行。如果多次需要某个参数,则该参数将被多次求值。请参阅:http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name
通话-by-need 大致相同,只是传递的对象是一个承诺,并且不会被评估超过一次;在随后引用参数时,将使用记忆值。请参阅:http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need
Call-by-name is a function calling discipline where when a call is made to a receving function foo, instead of the arguments to foo being evaluated, foo receives (behind the scenes) an appropriate object that will allow it to evaluate the parameters it needs; or equivalently, evaluation progresses by macro substitution. If a parameter is required more than once, it will be evaluated more than once. See: http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name
Call-by-need is much the same, except that the object passed is a promise, and will be evaluated no more than once; on subsequent references to a parameter, the memoised value is used. See: http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need
首先,call-by-need或者call-by-name都代表了延迟求值的实现方式,所以有必要知道什么是惰性评估 ...
You can see call-by-need in Haskell for example and call-by-name in Scala.
按需调用可能是实现惰性的预期方式。当您第一次“真正”需要该值时,您会计算它并缓存计算值以供将来访问。
当您使用按名称调用时,您不会执行这种缓存,而是每次在函数体中使用函数参数时都会对其进行求值。可能会认为它没有意义,但是将一些流控制结构实现为语言的函数是有用的,比如说一段时间。
然后你可以调用函数 myWhile,
如果我们在上面的示例中使用了按名称调用,则表达式“cond”不会被缓存,并且每次需要时都会对其进行求值。
First of all, either call-by-need or call-by-name represent ways of implementing lazy-evaluation, so it necessary to know what is lazy-evaluation ...
You can see call-by-need in Haskell for example and call-by-name in Scala.
call-by-need is maybe the expected way of implementing laziness. The first time you "really" need the value, you computed it and you make a cache of the computed value for future access.
when you have call-by-name you don't perform this sort of caching, you evaluate the function arguments every time they are used in the function body. It is possible to think that it does not have sense, but it is useful to implement some flow control structure as function of the language, let say a while.
And then you can call the function myWhile,
If we had call-by-name for the example above, the expression "cond" is not cached and it is evaluated each time is needed.
按名称调用和按需要调用都类似于宏扩展。但是在按需要调用中,一旦对值进行求值,它就会记住该值并在下次使用该值。
例如:-2003 号门有一个问题。
按姓名呼叫:
在函数中代替 x 时,它变为 i+j 所以第一次打印将是 i+j+10=10+5+10=25 ,下一次打印将是 i+j=200+ 20
产量:25,220
按需求调用:
代替 x,它变成 i+j,第一次打印后,x 即 i+j 值变成 15,它会记住它。
所以输出将是
输出:25,15
Both call by name and call by need is like macro expansion.But in call by need once the value is evaluated it memoized the value and use this value next time.
for eg:-there is a question in gate 2003.
CALL BY NAME:
in place of x in function it becomes i+j so first print will be i+j+10=10+5+10=25 and next print will be i+j=200+20
output:25,220
CALL BY NEED:
in place of x it becomes i+j and after first print ,x i.e. i+j value becomes 15 it memoized it.
so output will be
output:25,15
在按需调用中,我们进入循环,并且仅对值求值一次。因此,在上面的代码中,我们将在循环内复制
(2*n)
(宏样式),并且仅对表达式求值一次(与按名称调用不同)。因此,在第一次迭代中我们将得到
e=2
。这也将是下一次迭代中e
的值,输出将为:In call by need, we enter the loop, and evaluate the value only once. So In the code above, we will copy
(2*n)
inside the loop (macro-style) and we will evaluate the expression only one time (Not like call by name).So, in the first iteration we will get
e=2
. this will be the value ofe
also in the next iteration, and the output will be: