这将在按名称调用和按值调用下打印什么?

What would this print under call-by-name and call-by-value?

我有这行代码是一种玩具语言。 print-函数获取参数列表并打印这些参数。

print(a, (a := 5, a))

如果我使用按值调用或按名称调用,输出会有所不同吗?如果是这样,输出会是什么。

可以假设a初始化为0

使用 "call-by-value" 参数 通常 从左到右求值(在大多数语言中),因此表达式等价于这样的东西:

arg1 := a // copy value of a to arg1
a := 5 // copy 5 to a
arg2 := a // copy value of a to arg2
print(arg1, arg2) // print(0, 5)

"call-by-name" 显然是惰性求值的一种形式,它会产生如下结果:

arg1 := function() {return a;}
arg2 := function() {a := 5; return a;}
print(arg1, arg2)

所以在这种情况下,结果将取决于两件事:

  • 在这种语言中,闭包是通过引用还是通过值捕获变量。如果按值捕获,a := 5 不会影响第一个闭包捕获的 a 的值。但是,大多数允许重新分配局部变量的语言都实现了按引用捕获(例如 JavaScript)。
  • print 函数决定对其参数求值的顺序 - 取决于它的编写方式。

如果闭包按值捕获,print(…) 将产生 0 5,因为赋值 a := 5 仅影响 a.[=27 的第二个闭包副本=]

如果闭包通过引用捕获,那么我只能猜测输出可能是什么。但是 print 函数很可能会做这样的事情:

print := function(lazy x, lazy y) {
    writeToOutput(x())
    writeToOutput(y())
}

在这种情况下,结果将是相同的 (0 5),因为首先计算 x(),处理结果,然后计算 y()。在这种情况下,a 的值在使用 x.

完成函数之前不会改变

但这只是一个猜测; print 可以按任何顺序(和任意次数)评估它们。