这将在按名称调用和按值调用下打印什么?
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
可以按任何顺序(和任意次数)评估它们。
我有这行代码是一种玩具语言。 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
可以按任何顺序(和任意次数)评估它们。