我有这行玩具语言代码。 print
函数接受参数列表并打印它们。
打印(a, (a := 5, a))
如果我使用按值调用或按名称调用,输出会有差异吗?如果是这样,输出是什么。
可以假设a
被初始化为0
。
最佳答案
对于“按值调用”参数,通常从左到右计算(在大多数语言中),因此表达式等效于如下内容:
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
副本。
如果闭包通过引用捕获,那么我只能猜测输出可能是什么。但 print
函数很可能会执行如下操作:
print := function(lazy x, lazy y) {
writeToOutput(x())
writeToOutput(y())
}
在这种情况下,结果将是相同的 (0 5
),因为首先评估 x()
,处理结果,然后处理 y()
被评估。在这种情况下,直到使用 x
完成函数之后,a
的值才会更改。
但这只是一个猜测; print
可以按任何顺序(以及任意次数)对它们进行评估。
关于compiler-construction - 在按名称调用和按值调用下会打印什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39411960/