编译高阶函数调用时,是否有一种标准方式处理单独编译和不同类型闭包转换之间的交互?高级函数调用的闭包转换和单独编译
我知道在大多数编程语言中明确编译的三个函数类构造:闭包,(顶级)函数和C++风格的函数对象。在语法上,他们被称为以同样的方式,但是编译器会优化产生明显形通话网站:
Syntax: | clo(args) | func(args) | obj(args)
--------------------------------------------------------------------------------
Codegen: | clo.fnc(&clo.env, args) | func(args) | cls_call(&obj, args)
^ ^ ^ ^ ^
fn ptr | +--"top level" fn --+ |
+--- "extra" param, compared to source type -----+
(在C++中,cls_call
将T::operator()
为obj
的类T
C++还允许虚拟函子,但这是。基本上封闭壳体与一个额外的间接。)
此时,调用map (x => x > 3) lst
和map (x => x > y) lst
应该调用不同map
的功能,这是因为第一是吊装后一个简单的函数的指针,和第二个是一个封闭。
我能想到的处理这个问题的四种方式:
的C++(98)的方法,这迫使被叫方要么选择一个调用点形状(通过形式参数类型:虚拟函子,函数指针或非虚拟函子),或者使用模板删除单独的编译,从而有效地指定下面的解决方案#2。
重载:编译器可以用
map
和所有其他高阶函数,并使用适当的名称修改来执行多重实例化。实际上,每个调用站点形状都有一个单独的内部函数类型,重载决策选择正确的一个。强制全球统一的呼叫站点形状。这意味着即使所有顶层函数都不需要它,也需要明确的
env
参数,并且必须引入“额外”闭包来包装非闭包参数。保留顶层函数的“自然”签名,但要求通过闭包完成所有高阶函数参数的处理。已关闭函数的“额外”闭包调用封装trampoline函数来丢弃未使用的
env
参数。这似乎比选项3更优雅,但难以有效实施。或者编译器生成调用约定-上独立包装的多个,或它使用少量的调用约定敏感的thunk的...
具有优化闭合转换/λ提升混合方案,用每个函数选择是否在ENV或参数列表中粘贴给定的闭包参数似乎会使问题更加尖锐。
不管怎么说,问题:
- 难道这一问题在文献中一个明确的名称?
- 除了上述四个之外,还有其他方法吗?
- 在方法之间是否有众所周知的折衷?