简体   繁体   中英

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. 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 f(...); return is amendable to this. It works for any f , even for function pointers/closures/virtual methods where the compiler can't possibly know what is being called. 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. 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; no recursion is necessary anywhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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