简体   繁体   English

除尾递归之外的尾调用优化?

[英]Tail call optimization besides tail recursion?

Are there any tail call optimizations possible besides tail recursion? 除了尾递归之外,还有可能进行尾调用优化吗? I've been trying to find or think of one that doesn't involve recursion, but with no success. 我一直试图找到或想到一个不涉及递归的,但没有成功。 Is it possible? 可能吗? Any examples? 任何例子?

Sure, "tail call optimization" is in fact the term for this kind of optimization in its most general, recursion-agnostic form. 当然,“尾部调用优化”实际上是这种优化的术语,以其最普遍的,递归不可知的形式。 This optimization doesn't replace recursion with the equivalent of a while loop or something like that. 此优化不会使用等效的while循环或类似的东西替换递归。 Instead, tail calls are transformed such that the caller's stack frame is re-used. 而是转换尾部调用,以便重新使用调用者的堆栈帧。 Any code of the form return f(...) or f(...); return 任何形式的代码都return f(...)f(...); return f(...); return is amendable to this. f(...); return可以修改。 It works for any f , even for function pointers/closures/virtual methods where the compiler can't possibly know what is being called. 它适用于任何 f ,甚至是函数指针/闭包/虚拟方法,其中编译器不可能知道被调用的内容。 Therefore it also works better with separate compilation, higher-order functions, late binding, etc. 因此,它也可以更好地与单独的编译,高阶函数,后期绑定等。

If you look at enough code, be it functional or imperative, you'll find occasional calls which aren't followed by anything. 如果你看一下足够多的代码,无论是功能性的还是命令式的,你都会偶尔看到一些没有任何代码的电话。 A common case is when the caller delegates to the callee for the main task and only does some additional preparations. 一个常见的情况是,调用者委托被调用者执行主任务,并且只做一些额外的准备工作。 In functional code, you'll often find many small functions which do only one thing and are implemented in terms of other small functions, so you wind up with several layers of applying a simple transformation to the arguments, then performing a tail call to the next layer (with the transformed data as argument). 在功能代码中,你经常会发现许多小函数只做一件事并且是用其他小函数实现的,所以你最后应用了一些简单的转换到参数,然后执行一个尾调用。下一层(将转换后的数据作为参数)。 TCO optimizes the second step, it (ideally) makes the call as cheap as a simple jump and makes the nice, modular code take as little stack space than a more monolithic implementation. TCO优化了第二步,它(理想情况下)使得调用像简单的jump一样便宜,并使得漂亮的模块化代码占用的堆栈空间比单片实现更少。 In an object oriented design you may want to compose an object of other objects and expose convenience methods that delegate: 在面向对象的设计中,您可能希望组合其他对象的对象并公开委派的便捷方法:

SomeClass doSomething(Argument a) {
    log.debug("Doing something");
    return this.somethingDoer.doIt(a, this.someExtraData);
}

Another example that's technically mutually recursive, but usually only has very few activations of any given function (with dozens or hundreds of other activations in between), are state machines implemented by having a function per state and calling it to enter that state: 另一个技术上相互递归的例子,但通常只有很少的任何给定函数的激活(其间有数十或数百个其他激活),是通过每个状态具有一个函数并调用它进入该状态来实现的状态机:

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 can simply jump to bar who returns to the caller directly; foo可以简单地跳转到直接返回调用者的bar ; no recursion is necessary anywhere. 任何地方都不需要递归。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM