Compiler construction “按名称调用”和“按值调用”下的打印内容是什么?
我用玩具语言编写了这行代码。Compiler construction “按名称调用”和“按值调用”下的打印内容是什么?,compiler-construction,functional-programming,sml,callbyname,call-by-value,Compiler Construction,Functional Programming,Sml,Callbyname,Call By Value,我用玩具语言编写了这行代码。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(a
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)
arg1 := function() {return a;}
arg2 := function() {a := 5; return a;}
print(arg1, arg2)
print := function(lazy x, lazy y) {
writeToOutput(x())
writeToOutput(y())
}
“按名称调用”显然是一种惰性评估,它会产生如下结果:
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)
arg1 := function() {return a;}
arg2 := function() {a := 5; return a;}
print(arg1, arg2)
print := function(lazy x, lazy y) {
writeToOutput(x())
writeToOutput(y())
}
因此,在这种情况下,结果将取决于两件事:
- 在这种语言中,闭包是通过引用还是通过值捕获变量。如果按值捕获,则
不会影响第一个闭包捕获的a:=5
的值。然而,大多数允许重新分配局部变量的语言都实现了引用捕获(例如JavaScript)a
函数决定对其参数求值的顺序取决于它的编写方式print
打印(…)
将产生05
,因为赋值a:=5
只影响a
的第二个闭包副本
如果闭包通过引用捕获,那么我只能猜测输出可能是什么。但是,print
函数很可能会执行如下操作:
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)
arg1 := function() {return a;}
arg2 := function() {a := 5; return a;}
print(arg1, arg2)
print := function(lazy x, lazy y) {
writeToOutput(x())
writeToOutput(y())
}
在这种情况下,结果将是相同的(05
),因为首先计算x()
,然后处理结果,然后计算y()。在这种情况下,a
的值只有在使用x
完成该功能后才会改变
但这只是猜测print
可以按任何顺序(和任何次数)对其进行评估。取决于print
的实施情况,您对此持什么立场?你读过关于评估策略的哪些材料,还有什么还不清楚?我正在为一个项目编写一个编译器,有人告诉我,在“按名称调用”中,它将打印05
,而在“按值调用”中,它将打印55
。他的论点是,在“按值调用”下,它将首先计算所有表达式,然后打印结果。这是真的吗?如果真的有,他似乎是颠倒过来了。具有严格求值和参数从左到右求值的按值调用将传递0
和5
。我认为“按名称调用”意味着通过引用传递参数,但实际上它意味着对参数的惰性求值,在函数体中,参数每“使用”一次都会求值一次。术语“通常是左到右(在大多数语言中)),著名的反例是C、C++和OCaml。在这些语言中,函数参数的求值顺序是未指定的(通常实现为从右到左)。@sepp2k:还有scheme和friends