F#でのY Combinatorの定義は次のとおりです。
let rec y f x = f (y f) x
fは、最初の引数として、再帰的な副問題の継続があることを期待しています。 y fを継続として使用すると、開発できるようにfが連続する呼び出しに適用されることがわかります
let y f x = f (y f) x = f (f (y f)) x = f (f (f (y f))) x etc...
問題は、先験的に、このスキームが末尾呼び出しの最適化を使用できないことです。実際、fで保留中の操作がある可能性があります。この場合、fに関連付けられたローカルスタックフレームを単に変更することはできません。
そう :
これらの2つを調整する方法を知っていますか?アキュムレータトリックを持つY、またはCPSトリックを持つYのように?または、それを行う方法がないことを証明する議論?
これら2つを調整する方法を知っていますか?
いいえ、そして正当な理由で、私見です。
Y-combinatorは理論上の構成要素であり、ラムダ計算を完全に処理するためにのみ必要です(ラムダ計算にはループがなく、ラムダには再帰に使用できる名前がないことに注意してください)。
このように、Y Combinatorは本当に魅力的です。
しかし:実際にはだれも使用実際の再帰のためのY結合子! (多分楽しみのためを除いて、それが本当に機能することを示すために。)
末尾呼び出しの最適化であるOTOHは、その名前が示すように、最適化です。それは言語の表現力に何も追加しません。それは私たちが気にかけているのは、スタック空間や再帰的コードのパフォーマンスなどの実用的な考慮事項のためだけです。
だからあなたの質問は次のようなものです:ベータ削減のためのハードウェアサポートはありますか? (ベータ削減とは、ラムダ式を削減する方法です。)しかし、関数型言語(私が知る限り)は、実行時にベータ削減されるラムダ式の表現にソースコードをコンパイルしません。
この答えについては完全にはわかりませんが、私が思いつく最高の答えです。
Y Combinatorは本質的に怠惰です。厳密な言語では、遅延は手動で追加のラムダを介して追加する必要があります。
let rec y f x = f (y f) x
定義は終了するために遅延が必要であるように見えます。そうでない場合、(y f)
引数は評価を終了せず、f
がそれを使用したかどうかを評価する必要があります。レイジーコンテキストでのTOCはより複雑であり、さらに(y f)
の結果は、x
を適用せずに繰り返し関数合成されます。これにO(n) memoryが必要かどうかはわかりませんが、nは再帰の深さです)(switching with私は実際にはF#を知らないのでHaskellに)
length acc [] = acc
length acc (a:b) = length (acc+1) b
まだ気付いていない場合は、Haskellでのfoldl
とfoldl'
の違いが状況に光を当てるかもしれません。 foldl
は、熱心な言語で行われるように書かれています。しかし、TOCされる代わりに、アキュムレータは部分的に評価できない潜在的に巨大なサンクを格納するため、実際にはfoldr
よりも悪いです。 (これは、foldlとfoldl 'の両方が無限リストで機能しない理由に関連しています。)したがって、Haskellのより最近のバージョンでは、foldl'
が追加され、関数が繰り返されるたびにアキュムレータの評価を強制して、巨大でないことを確認します。サンクが作成されます。きっと http://www.haskell.org/haskellwiki/Foldr_Foldl_Foldl%27 私よりもこのことをよく説明できるでしょう。