これはTail Recursion ModuloConsと呼ばれます。基本的に、再帰呼び出しの直後にリストに追加することは、再帰呼び出しの直前にリストに追加することと同じです(したがって、純粋に機能的な「ループ」の「副作用」としてリストを作成します)。これは末尾再帰の一般化であり、リストだけでなく、定数操作を伴うデータ コンストラクターでも機能します。cons
これは、1974 年に Daniel P. Friedman と David S. Wise によってテクニカル レポート TR19: Unwinding Structured Recursions into IterationsでLISP コンパイル手法として最初に説明されました (名前は付けられていません)。史上初の Prolog コンパイラを作成するコンテキスト。
ただし、Oz の興味深い点は、TRMC が言語機能でも明示的なコンパイラの最適化でもなく、言語の実行セマンティクスの単なる副作用であることです。特に、Oz が宣言型の同時制約言語であるという事実は、すべての変数がデータフロー変数であることを意味します (または、すべての保存場所を含む「すべてが約束です」)。すべてが promise であるため、最初に戻り値を promise として設定し、後でそれを実行するように、関数からの戻りをモデル化できます。
Peter Van Roy と Seif Haridi による本Concepts, Techniques, and Models of Computer Programmingの共著者である Peter van Roy は、Oz の設計者の 1 人であり、その実装者の 1 人でもあり、TRMC がどのように正確に機能するかをコメント スレッドで説明しています。 Lambda the Ultimate:末尾再帰マップと宣言型エージェント:
上記の不適切な Scheme コードの例は、Oz 構文に直接変換すると、適切な末尾再帰 Oz コードに変わります。これは与える:
fun {Map F Xs}
if Xs==nil then nil
else {F Xs.1}|{Map F Xs.2} end
end
これは、Oz に単一代入変数があるためです。実行を理解するために、この例を Oz カーネル言語に翻訳します (わかりやすくするために、部分的な翻訳のみを示しています)。
proc {Map F Xs Ys}
if Xs==nil then Ys=nil
else local Y Yr in
Ys=Y|Yr
{F Xs.1 Y}
{Map F Xs.2 Yr}
end end
end
つまり、最初はバインドされていないMapため、末尾再帰です。Yrこれは単なる巧妙なトリックではありません。宣言型の同時実行と宣言型のマルチエージェント システムが可能になるため、非常に重要です。