在按名称和按值调用的情况下打印什么?

时间:2016-09-09 12:46:46

标签: compiler-construction functional-programming sml callbyname call-by-value

我用玩具语言编写这行代码。 print - 函数接受一个参数列表并打印出来。

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

如果我使用call-by-value或call-by-name,输出会有区别吗?如果是这样,产出会是什么。

可以假设a已初始化为0

1 个答案:

答案 0 :(得分:4)

使用“按值调用”参数通常从左到右(在大多数语言中)进行评估,因此表达式将等同于:

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()。在这种情况下,a的值直到函数完成x后才会更改。

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