首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >按需呼叫与按名称呼叫

按需呼叫与按名称呼叫
EN

Stack Overflow用户
提问于 2012-01-02 22:11:19
回答 4查看 12.7K关注 0票数 20

我不明白Call-by-name和Call-by-need之间的区别。据我所知,Call-by-need方法会恢复返回的结果。但是它是如何帮助我们的,结果之间有什么根本的区别吗?

例如,

代码语言:javascript
复制
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

因此,根据我的理解,在call-by-name中,我们将得到:

代码语言:javascript
复制
;;; the value of e is 2
;;; the value of e is 4
;;; the value of e is 8

诸若此类。这是因为我们将2*n传递给e,并且每次都使用新的ie求值。在call-by-need中会发生什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-01-06 05:16:59

在call by need中,我们进入循环,并且只计算一次值。因此,在上面的代码中,我们将在循环内复制(2*n) (宏样式),并且我们将只计算表达式一次(不像按名称调用)。因此,在第一次迭代中,我们将得到e=2。这也将是下一次迭代中e的值,输出将是:

代码语言:javascript
复制
;;; the value of e is 2
;;; the value of e is 2
;;; the value of e is 2
票数 -2
EN

Stack Overflow用户

发布于 2012-01-12 19:14:51

您的困惑似乎源于您在imperative上下文中思考的事实。关于按需调用与按值调用的讨论主要涉及声明性和函数式语言,以及lambda演算。

您可以在这篇关于evaluation strategies的文章中看到,按名称调用和按需要调用都被认为是懒惰的评估策略。惰性求值意味着当表达式作为参数传递给函数时,在进入函数体之前不会对其求值,而只是在函数内部第一次访问/读取时才进行求值。如果这样的表达式的结果从未在内部使用过,那么它将永远不会被计算。

例如,? :操作符在Java语言中是惰性的,如下面的代码所示:

代码语言:javascript
复制
String test(Object obj)
{
    return 1 == 2 ? obj.toString() : "Hello World";
}

test(null); // this won't throw a NullPointerException

按需调用是大多数具有纯子集的函数式语言的基本特性。在purely functional language中,每个函数都必须是referentially transparent,即它们不能有side-effects。这样的pure functions具有这样的特性:对于某些给定的输入,它们总是返回相同的输出,无论调用多少次,并且它们永远不会改变“世界状态”中的任何东西。它们的行为就像纸上写的数学函数。

正如您已经意识到的那样,在调用非纯函数时,按需调用策略是不可行的,因为您很可能对连续调用带来的副作用感兴趣。另一方面,当在纯函数式语言中使用时,它成为性能的基本特性(参见下面的第二个示例)。另外,请参阅这些关于Graph ReductionMemoization概念的维基页面。

真实世界的例子

使用图形归约的常用系统的一个例子是Apache Ant。Ant不会对一个目标进行两次评估。这种设计使得绘制一个声明性的构建计划变得很方便。

Second。如果你想看一个很好的记忆演示,在GHC解释器中输入这段Haskell代码,看看会发生什么:

代码语言:javascript
复制
Prelude> let fibs = 0:1:(zipWith (+) fibs (tail fibs))
-- This defines the Fibonacci sequence.
Prelude> fibs !! 200000
-- Prints the 200,000th Fibonacci number,
-- takes several seconds to calculate.
Prelude> fibs !! 200000
-- Prints the same number as before,
-- but this time it returns immediately.

注意:您可能还听说过按值调用的评估策略。与按名称调用和按需调用相比,按值调用是一种严格的评估策略。它类似于按名称调用,因为多次调用会导致多次求值。对于习惯于C#或Java等命令式语言的程序员来说,这是最常见的范例。

票数 9
EN

Stack Overflow用户

发布于 2012-01-12 00:24:54

Call- by -name是一种调用规程的函数,当调用接收函数foo时,foo (而不是正在计算的foo的参数)将(在幕后)接收一个适当的对象,该对象将允许它计算它需要的参数;或者等效地,计算通过宏替换进行。如果一个参数被多次需要,它将被多次求值。请参阅:http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name

按需调用大致相同,不同之处在于传递的对象是一个promise,并且只会被计算一次;在随后引用参数时,将使用已记忆的值。请参阅:http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8701834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档