我查了维基百科,然后用Google搜索,但我还是无法理解ALGOL 60中的名字传递方式。
答案 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)
,我们将i
和i/2
传递给i
,其中10
最初等于f
。如果x
将42
设置为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 ++的传递引用相同。