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

末尾再帰は、関数がある程度の作業を行ってから、それ自体を呼び出す再帰的な戦略です。「テール」とは、再帰が関数の最後にあるという事実を指します。多くの(特に関数型)プログラミング言語コンパイラは、これらのタイプの呼び出しを反復に変えることができます。つまり、呼び出しの数に関係なく、サポートされている言語での末尾再帰をスタックオーバーフローを恐れずに使用できます。



19
Scalaでループから抜け出すにはどうすればよいですか?
ループを解除するにはどうすればよいですか? var largest=0 for(i<-999 to 1 by -1) { for (j<-i to 1 by -1) { val product=i*j if (largest>product) // I want to break out here else if(product.toString.equals(product.toString.reverse)) largest=largest max product } } ネストされたforループをテール再帰に変換するにはどうすればよいですか? 22ページ目のFOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261でのScala Talkから: 中断して続行Scalaにはありません。どうして?それらは少し必須です。多くの小さな関数をより適切に使用するクロージャとの相互作用方法を発行します。それらは必要ありません! 説明は何ですか?

20
再帰を理解する[終了]
現在のところ、この質問はQ&A形式には適していません。私たちは回答が事実、参考文献、または専門知識によってサポートされることを期待しますが、この質問はおそらく議論、議論、投票、または拡張された議論を誘います。この質問を改善でき、再開できると思われる場合は、ヘルプセンターにアクセスしてください。 7年前休業。 学校での再帰の理解に大きな問題があります。教授が話をしているときはいつでもそれを理解しているようですが、自分で試してみるとすぐに完全に頭が痛くなります。 私はハノイの塔を一晩中解決しようとしていて、心を完全に吹き飛ばしました。私の教科書は再帰が約30ページしかないので、あまり役に立ちません。このトピックを明確にするのに役立つ本やリソースを知っている人はいますか?

6
Pythonは末尾再帰を最適化しますか?
次のエラーで失敗する次のコードがあります。 RuntimeError:再帰の最大深度を超えました これを書き直して、末尾再帰の最適化(TCO)を可能にしようとしました。TCOが発生した場合、このコードは成功したはずです。 def trisum(n, csum): if n == 0: return csum else: return trisum(n - 1, csum + n) print(trisum(1000, 0)) PythonはどのタイプのTCOも実行しないと結論付けるべきでしょうか、それとも単に異なる方法で定義する必要があるだけでしょうか?

5
もしあれば、C ++コンパイラーが末尾再帰の最適化を行いますか?
CとC ++の両方で末尾再帰の最適化を行うことは完全にうまくいくように思えますが、デバッグ中は、この最適化を示すフレームスタックが表示されないようです。スタックが再帰の深さを教えてくれるからです。ただし、最適化も同様によいでしょう。 C ++コンパイラーはこの最適化を行いますか?どうして?何故なの? コンパイラーに指示する方法を教えてください。 MSVCの場合:/O2または/Ox GCCの場合:-O2または-O3 コンパイラが特定のケースでこれを行ったかどうかを確認するのはどうですか? MSVCの場合、PDB出力がコードをトレースできるようにしてから、コードを検査します GCC ..? 特定の関数がコンパイラーによってこのように最適化されているかどうかを判断する方法については引き続き提案します(Konradがそれを想定するように指示していることを確信しているにもかかわらず) 無限再帰を行って無限ループまたはスタックオーバーフローが発生するかどうかを確認することで、コンパイラーがこれを実行するかどうかを常に確認することができます(GCCでこれを実行し、それで-O2十分であることがわかりました)。とにかく終了することがわかっている特定の機能をチェックできます。これをチェックする簡単な方法が欲しいです:) いくつかのテストの後、デストラクタがこの最適化を行う可能性を台無しにしていることを発見しました。特定の変数と一時オブジェクトのスコープを変更して、return-statementが始まる前にスコープから外れるようにすることは、価値がある場合があります。 末尾呼び出しの後にデストラクタを実行する必要がある場合、末尾呼び出しの最適化は実行できません。

8
末尾再帰はどの程度正確に機能しますか?
末尾再帰がどのように機能するか、および通常の再帰との違いをほぼ理解しています。私は唯一それが理由を理解していないしないそのリターンアドレスを覚えてスタックを必要としています。 // tail recursion int fac_times (int n, int acc) { if (n == 0) return acc; else return fac_times(n - 1, acc * n); } int factorial (int n) { return fac_times (n, 1); } // normal recursion int factorial (int n) { if (n == 0) return 1; …

6
.NET / C#が末尾呼び出しの再帰に対して最適化しないのはなぜですか?
どの言語が末尾再帰を最適化するかについて、この質問を見つけました。なぜC#は可能な限り末尾再帰を最適化しないのですか? 具体的なケースでは、なぜこのメソッドがループに最適化されていないのですか(Visual Studio 2008 32ビット、重要な場合)?: private static void Foo(int i) { if (i == 1000000) return; if (i % 100 == 0) Console.WriteLine(i); Foo(i+1); }

5
JVMは末尾呼び出しの最適化を妨げますか?
私はこの質問でこの引用を見ました:Webサービスを構築するための優れた関数型言語は何ですか? 特にScalaは、自己再帰関数を除き、末尾呼び出しの除去をサポートしていません。これにより、実行できる構成の種類が制限されます(これは、JVMの基本的な制限です)。 これは本当ですか?もしそうなら、この基本的な制限を作成するのはJVMについて何ですか?

5
Rubyはテールコールの最適化を実行しますか?
関数型言語は、多くの問題を解決するために再帰を使用することになるため、それらの多くはTail Call Optimization(TCO)を実行します。TCOは、その関数の最後のステップとして、新しいスタックフレームを必要としないように、別の関数(またはこの関数自体、この機能はTCOのサブセットであるテール再帰除去とも呼ばれます)から関数を呼び出します。オーバーヘッドとメモリ使用量が減少します。 Rubyは明らかに関数型言語から多くの概念(ラムダ、マップなどの関数など)を「借用」しているため、奇妙なことに、Rubyは末尾呼び出しの最適化を実行しますか?


4
Haskellには末尾再帰最適化がありますか?
今日、UNIXで「time」コマンドを発見し、Haskellの末尾再帰関数と通常の再帰関数のランタイムの違いを確認するのに使用すると思いました。 私は以下の関数を書きました: --tail recursive fac :: (Integral a) => a -> a fac x = fac' x 1 where fac' 1 y = y fac' x y = fac' (x-1) (x*y) --normal recursive facSlow :: (Integral a) => a -> a facSlow 1 = 1 facSlow x = x * …

1
Scala Cats / fs2でスタックの安全性を推論する方法は?
以下はfs2のドキュメントからのコードの一部です。関数goは再帰的です。問題は、それがスタックセーフであるかどうかをどのように知るか、および関数がスタックセーフかどうかをどのように推論するかです。 import fs2._ // import fs2._ def tk[F[_],O](n: Long): Pipe[F,O,O] = { def go(s: Stream[F,O], n: Long): Pull[F,O,Unit] = { s.pull.uncons.flatMap { case Some((hd,tl)) => hd.size match { case m if m <= n => Pull.output(hd) >> go(tl, n - m) case m => Pull.output(hd.take(n.toInt)) >> Pull.done } case None …

2
Rustでテール再帰はいつ保証されますか?
C言語 Cプログラミング言語では、末尾再帰を行うのは簡単です。 int foo(...) { return foo(...); } 再帰呼び出しの戻り値と同じように戻ります。この再帰が1000回または100万回繰り返される場合は特に重要です。スタックで大量のメモリを使用します。 さび これで、100万回再帰的に呼び出されるRust関数があります。 fn read_all(input: &mut dyn std::io::Read) -> std::io::Result<()> { match input.read(&mut [0u8]) { Ok ( 0) => Ok(()), Ok ( _) => read_all(input), Err(err) => Err(err), } } (これは最小限の例であり、実際の例はより複雑ですが、主なアイデアを捉えています) ここでは、再帰呼び出しの戻り値がそのまま返されますが、次のようになります。 Rustコンパイラが末尾再帰を適用することを保証しますか? たとえば、のように破棄する必要がある変数を宣言した場合、std::Vecそれは再帰呼び出しの直前(末尾再帰を可能にする)または再帰呼び出しが戻った後(末尾再帰を禁止する)に破棄されますか?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.