末尾再帰以外に末尾呼び出しの最適化はありますか? 私は再帰を含まないものを見つけたり考えたりしようとしましたが、成功しませんでした。出来ますか?例はありますか?
2 に答える
確かに、「末尾呼び出しの最適化」は、実際には、この種の最適化の最も一般的な、再帰にとらわれない形式の用語です。while
この最適化は、再帰をループなどに相当するものに置き換えません。代わりに、末尾の呼び出しは、呼び出し元のスタック フレームが再利用されるように変換されます。またはの形式のコードは、これに修正可能です。これは、関数ポインター/クロージャー/仮想メソッドであっても、コンパイラーが何が呼び出されているかを知ることができない場合でも機能します。したがって、個別のコンパイル、高階関数、遅延バインディングなどでもうまく機能します。return f(...)
f(...); return
f
機能的であろうと命令的であろうと、十分なコードを見ると、何も続かない呼び出しが時折見つかることがわかります。一般的なケースは、呼び出し元がメイン タスクの呼び出し先に委任し、いくつかの追加の準備のみを行う場合です。関数型コードでは、多くの場合、1 つのことだけを行い、他の小さな関数として実装されている多くの小さな関数を見つけることができます。そのため、引数に単純な変換を適用してから、末尾の呼び出しを実行するという複数のレイヤーが必要になります。次のレイヤー (変換されたデータを引数として)。TCO は 2 番目のステップを最適化し、(理想的には) 呼び出しを単純なほど安価にします。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