【发布时间】:2013-08-04 20:42:31
【问题描述】:
除了尾递归之外,是否还有其他可能的尾调用优化?我一直在尝试寻找或想到一个不涉及递归但没有成功的方法。可能吗?有什么例子吗?
【问题讨论】:
-
Continuations 可能有资格进行尾调用优化。
标签: c++ c optimization compiler-construction tail-call-optimization
除了尾递归之外,是否还有其他可能的尾调用优化?我一直在尝试寻找或想到一个不涉及递归但没有成功的方法。可能吗?有什么例子吗?
【问题讨论】:
标签: c++ c optimization compiler-construction tail-call-optimization
当然,“尾调用优化”实际上是这种优化的最通用术语,与递归无关。这种优化不会用 while 循环或类似的东西代替递归。相反,尾调用被转换,使得调用者的堆栈帧被重新使用。 return f(...) 或 f(...); return 形式的任何代码都可以对此进行修改。它适用于 any f,甚至适用于编译器不可能知道正在调用什么的函数指针/闭包/虚拟方法。因此,它还可以更好地用于单独编译、高阶函数、后期绑定等。
如果您查看了足够多的代码,无论是函数式的还是命令式的,您都会发现偶尔会出现没有任何后续调用的调用。一个常见的情况是调用者将主要任务委托给被调用者,并且只做一些额外的准备工作。在函数式代码中,您经常会发现许多只做一件事并根据其他小函数实现的小函数,因此您最终需要对参数应用简单的转换,然后执行尾调用下一层(以转换后的数据为参数)。 TCO 优化了第二步,它(理想情况下)使调用与简单的jump 一样便宜,并使漂亮的模块化代码与更单一的实现相比占用更少的堆栈空间。在面向对象的设计中,您可能希望组合其他对象的对象并公开委托的便捷方法:
SomeClass doSomething(Argument a) {
log.debug("Doing something");
return this.somethingDoer.doIt(a, this.someExtraData);
}
另一个在技术上相互递归的示例,但通常只有很少的任何给定函数的激活(中间有数十或数百个其他激活),是通过每个状态具有一个函数并调用它进入该状态来实现的状态机:
void stateA() {
// do actual work
// determine which transition applies
stateB();
}
void stateB() {
// do actual work
// determine which transition applies
state...();
}
// dozens, possibly hundreds of other states
【讨论】:
int bar(int x);
int foo(int x) { return bar(x); }
foo 可以直接跳转到bar 直接返回给调用者;任何地方都不需要递归。
【讨论】:
bar的定义,只留下了它的声明。你不能在没有定义的情况下内联bar,但你可以对其调用者执行尾调用优化。看出区别了吗?