什么是“名字传递”,它是如何运作的?

时间:2009-05-08 03:16:06

标签: parameter-passing history pass-by-name algol

我查了维基百科,然后用Google搜索,但我还是无法理解ALGOL 60中的名字传递方式。

8 个答案:

答案 0 :(得分:36)

我在Pass-By-Name Parameter Passing找到了一个很好的解释。本质上,在文本上将实际参数替换为函数体之后,在调用时解释函数体。从这个意义上讲,评估方法类似于C预处理器宏。

通过将实际参数替换为函数体,函数体可以读取和写入给定的参数。在这个意义上,评估方法类似于传递参考。不同之处在于,由于在函数内部按名称传递参数 ,因此a[i]之类的参数取决于函数内i的当前值,而不是在调用函数之前引用a[i]处的值。

我上面链接的页面有一些更多的例子,说明pass-by-name既有用又危险。通过名称传递实现的技术在很大程度上被其他更安全的技术所取代,例如传递引用和lambda函数。

答案 1 :(得分:13)

我假设你的意思是ALGOL 60中的名字。

按名称调用类似于引用调用,因为您可以更改传入的参数的值。它与call-by-reference的不同之处在于,在调用过程之前参数是 not ,而是懒惰地进行评估。也就是说,仅当实际使用参数时才进行评估。

例如,假设我们有一个程序f(x, y),我们将ii/2传递给i,其中10最初等于f。如果x42设置为y,然后评估21,则会看到值5(而通过引用调用或按值调用它仍会看到i/2)。这是因为在评估y之前不会评估表达式real procedure Sum(k, l, u, ak) value l, u; integer k, l, u; real ak; comment k and ak are passed by name; begin real s; s := 0; for k := l step 1 until u do s := s + ak; Sum := s end;

在许多方面,这似乎表现得像参数的文字文本替换(重命名以避免名称冲突)。然而,在实践中,这是使用传入表达式的“thunks”(基本上是闭包)来实现的。

关于Jensen's Device的维基百科文章展示了一些使用名称调用的有趣例子。这是其中之一:

k
     

在该过程中,索引变量ak和求和项ak是   通过名字传递。按名称调用可使过程更改值   执行for循环期间的索引变量。按姓名呼叫   还会导致在每次迭代期间重新评估ak参数   循环。通常,k将取决于变化(副作用)   V[]

     

例如,用于计算真实的前100个项之和的代码   数组Sum(i, 1, 100, V[i]). 将是:

{{1}}

答案 2 :(得分:3)

对于未来的人:

编程语言中的概念 John C. Mitchell也很有帮助。

  

<强>传递通过-名称即可。也许是最奇怪的   回想起来,Algol 60的特点是   使用传递名称。在   按名称传递,结果   程序调用就好了   形式参数被代入   程序的主体。这个规则   用于定义过程的结果   通过复制程序来调用   代替形式参数   被称为Algol 60复制规则。   虽然复制规则适用于   纯粹的功能程序,如   通过λ减少λ来说明   微积分,与侧面的相互作用   对形式参数的影响是a   有点奇怪。这是一个例子   显示技术的程序   作为Jensen的装置:传递一个   表达式和它包含的变量   一个程序,以便程序   可以使用一个参数来改变   其他人提到的位置:

     
 begin integer i;
        integer procedure sum(i, j);
            integer i, j;
                comment parameters passed by name;
            begin integer sm; sm := 0;
                for i := 1 step 1 until 100 do sm := sm + j;
                sum := sm
            end;
        print(sum(i, i*10 ))
 end

  

在这个程序中,程序   sum(i,j)将j的值相加为i   从1到100。如果你看看   代码,你会意识到的   程序毫无意义,除非   改变我导致一些变化   j的值;否则,程序   只计算100 * j。在通话中   这里显示的sum(i,i * 10),for循环   在程序的总和中加起来   当我从1变为1时,i * 10的值   100。

答案 3 :(得分:2)

实际上,名字叫,不仅仅是历史的好奇心。您可以在Windows批处理文件(以及无数其他脚本语言)中按名称进行调用。知道它是如何工作的,以及如何在编程中有效地使用它可以为问题提供简洁的解决方案。我知道它只是为了以后的扩展而传递字符串,但是它可以被操作以具有与按名称调用类似的效果。

call :assign x 1
exit /b
:assign
setlocal enabledelayedexpansion
(endlocal
:: Argument 1 is the name of the variable
set %1=%2
)
exit /b

答案 4 :(得分:1)

Flatlander在Scala here中有一个很好的例子。假设你想在:

时实现
def mywhile(condition: => Boolean)(body: => Unit): Unit =
  if (condition) {
    body
    mywhile(condition)(body)
  }
     

我们可以这样称呼:

var i = 0
mywhile (i < 10) {
  println(i)
  i += 1
}

Scala不是Algol 60,但它可能会有所帮助。

答案 5 :(得分:1)

您可以在变量的符号形式中传递“name”,以便同时更新和访问它。举一个例子,假设您想要对变量x进行三重处理,其类型为int:

start double(x);
real x;
begin
x : = x * 3
end;

答案 6 :(得分:1)

ALGOL专为数学算法而设计。我喜欢求和函数作为名称调用的一个例子。

抱歉,我的ALGOL有点生疏,语法可能不对。

.FUNCTION SUM(var,from,to,function)
.BEGIN
  .REAL sum =0;
  .FOR var = from .TO to .DO sum = function;
  return sum;
.END

你可以使用像

这样的总和
  Y = sum(x,1,4,sum(y,3,8,x+y));

在上面,内部和(y,3,8,x + y)将生成一个未命名的函数以传递给外部和调用。变量x和y不是按值传递,而是按名称传递。在变量的情况下,按名称调用等效于C中的地址引用调用。当涉及递归时,它会有点混乱。

Borrows制造了ALGOL机器。它们具有48位字存储器和3个标志位。标志位按名称ALGOL实现了cal。它是一个堆栈机器,所以当函数被加​​载到堆栈时,名称fag的调用将导致它被调用。当表达式用作参数时,编译器将生成未命名的函数。变量将是一个简单的间接引用。写入函数时会发生错误。

答案 7 :(得分:1)

我知道我加入俱乐部已经很晚了,这不一定是答案,但我确实想补充一点,这有助于澄清一点。我一直认为Algol传递名称是一个类似的过程,当C ++预处理器指令(特别是宏)用编译时的实际代码片段替换某个函数/变量的名称时。 pass-by-name基本上用形式的参数替换形式参数的名称,然后执行。我从来没有用Algol写过,但我听说按名称传递的结果与C ++的传递引用相同。