タグ付けされた質問 「tail-call」

8
再帰アルゴリズムでスタックオーバーフローを回避するための方法は何ですか?
質問 再帰アルゴリズムによって引き起こされるスタックオーバーフローを解決する可能な方法は何ですか? 例 Project Eulerの問題14を解決しようとしていますが、再帰アルゴリズムを使用して試してみることにしました。ただし、プログラムはjava.lang.StackOverflowErrorで停止します。分かりました。非常に大きな数のCollat​​zシーケンスを生成しようとしたため、アルゴリズムは実際にスタックをオーバーフローさせました。 解決策 だから私は疑問に思っていました:あなたの再帰アルゴリズムが正しく書かれており、常にスタックをオーバーフローさせると仮定して、スタックオーバーフローを解決するための標準的な方法は何ですか?思いついた2つの概念は次のとおりです。 末尾再帰 繰り返し アイデア(1)と(2)は正しいですか?他のオプションはありますか? 編集 できればJava、C#、Groovy、またはScalaでコードを表示すると役立ちます。 おそらく上記のプロジェクトオイラーの問題を使用しないでください。そうすれば、他の人にとっては甘やかされることはありませんが、他のアルゴリズムを使用できます。階乗かもしれない、または似たようなもの。

4
JVMがテールコールの最適化に課す制限
Clojureは、単独で末尾呼び出しの最適化を実行しません。末尾再帰関数があり、それを最適化する場合は、特別な形式を使用する必要がありますrecur。同様に、相互に再帰的な関数が2つある場合、を使用してのみ最適化できますtrampoline。 Scalaコンパイラは、再帰関数に対してTCOを実行できますが、2つの相互再帰関数に対してはできません。 これらの制限について読んだときはいつでも、JVMモデルに固有の制限に常に起因していました。コンパイラについてはほとんど何も知りませんが、これは少し困惑します。から例を見てみましょうProgramming Scala。ここで機能 def approximate(guess: Double): Double = if (isGoodEnough(guess)) guess else approximate(improve(guess)) に翻訳されています 0: aload_0 1: astore_3 2: aload_0 3: dload_1 4: invokevirtual #24; //Method isGoodEnough:(D)Z 7: ifeq 10: dload_1 11: dreturn 12: aload_0 13: dload_1 14: invokevirtual #27; //Method improve:(D)D 17: dstore_1 18: goto 2 そのため、バイトコードレベルでは、が必要gotoです。この場合、実際には、ハードワークはコンパイラーによって行われます。 基礎となる仮想マシンのどの機能により、コンパイラはTCOをより簡単に処理できますか? …
36 scala  clojure  jvm  tail-call 

2
Yコンビネーターとテールコールの最適化
F#のYコンビネーターの定義は let rec y f x = f (y f) x fは、最初の引数として、再帰的サブ問題の継続を期待しています。yfを継続として使用すると、fが次の呼び出しに適用され、開発できることがわかります。 let y f x = f (y f) x = f (f (y f)) x = f (f (f (y f))) x etc... 問題は、先験的に、このスキームがテールコールの最適化を使用できないことです。実際、fで保留中の操作がある可能性があります。その場合、fに関連付けられたローカルスタックフレームを変更できません。 そう : 一方では、Yコンビネータを使用するには、関数自体とは明示的に異なる継続が必要です。 TCOを適用する必要がある場合は、fで保留中の操作はなく、f自体のみを呼び出します。 これら2つを調整する方法を知っていますか?アキュムレータトリックを使用したYや、CPSトリックを使用したYなど?それともそれができる方法がないことを証明する議論?

3
関数呼び出しのセマンティクスを表すためにスタックを使用する代替策はどれですか?
通常、関数呼び出しは通常スタックを使用して実装されることを知っています。フレーム、リターンアドレス、パラメータ、ロットがあります。 ただし、スタックは実装の詳細です:呼び出し規則は異なることを行う場合があります(x86 fastcallは(一部の)レジスタを使用し、MIPSとフォロワーはレジスタウィンドウを使用するなど)、最適化は他のこと(インライン化、フレームポインターの省略、テールコール最適化..)。 確かに、多くのマシン(JVMやCLRのようなVMだけでなく、PUSH / POPなどを備えたx86のような実際のマシン)に便利なスタック命令が存在するため、関数呼び出しに使用すると便利ですが、場合によっては可能ですコールスタックが不要な方法でプログラムする(ここでContinuation Passing Style、またはメッセージパッシングシステムのアクターについて考えています) だから、私は疑問に思い始めていました:スタックなしで関数呼び出しセマンティクスを実装することは可能ですか、それとも異なるデータ構造(キュー、おそらく、または連想マップ)を使用して良いですか? もちろん、スタックは非常に便利な(ユビキタスである理由があります)が、最近私は不思議に思う実装にぶつかりました。 言語/マシン/仮想マシンで行われたことがあるかどうか、知っている人はいますか?その場合、顕著な違いと欠点はどれですか? 編集:私の直感は、異なるサブ計算アプローチが異なるデータ構造を使用できるということです。たとえば、ラムダ計算はスタックベースではありません(関数の適用の考え方は簡約によってキャプチャされます)が、実際の言語/マシン/例を見ていました。それが私が尋ねている理由です...

4
TCOがない場合、スタックを爆破することを心配する場合
JVMを対象とする新しいプログラミング言語についての議論があるたびに、必然的に次のようなことを言っている人々がいます。 「JVMはテールコールの最適化をサポートしていないため、大量のスタックの爆発を予測しています」 そのテーマには何千ものバリエーションがあります。 今では、Clojureなどの一部の言語には、使用できる特別な再帰構造があります。 私が理解していないのは、テールコール最適化の欠如がどれほど深刻なのかということです。いつ心配する必要がありますか? 私の混乱の主な原因は、おそらくJavaがこれまでで最も成功した言語の1つであり、JVM言語のかなりの数がかなりうまくいっているように思われるという事実からでしょう。TCOの欠如が本当にあるならばどのようにそれが可能である任意の懸念?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.