実は、関数のエンコードに関しては、あまり余裕がありません。主なオプションは次のとおりです。
用語の書き換え:関数を抽象構文ツリー(またはその一部のエンコード)として保存します。関数を呼び出すときは、構文ツリーを手動で走査して、パラメーターを引数に置き換えます。これは簡単ですが、時間と空間の点で非常に非効率的です。 。
クロージャー:関数、おそらく構文ツリーを表現する何らかの方法があります。これらの関数では、何らかの方法で参照によって引数を参照します。ポインタオフセット、整数、またはDe Bruijnインデックス、名前の場合があります。次に、関数をクロージャとして表現します。関数の「命令」(ツリー、コードなど)は、関数のすべての自由変数を含むデータ構造とペアになります。関数が実際に適用されると、環境、ポインター演算などを使用して、データ構造内の自由変数を検索する方法がどういうわけかわかります。
他のオプションもあると思いますが、これらは基本的なオプションです。他のほとんどすべてのオプションは、基本的なクロージャー構造のバリアントまたは最適化になると思います。
したがって、パフォーマンスの点では、クロージャはほとんどの場合、用語の書き換えよりも優れたパフォーマンスを発揮します。バリエーションのうち、どちらが良いですか?それはあなたの言語とアーキテクチャに大きく依存しますが、「無料の変数を含む構造体を持つマシンコード」が最も効率的だと思います。関数が必要とするすべてのもの(命令と値)があり、それ以外には何もありません。また、呼び出しが大量の用語トラバーサルを実行することにはなりません。
現在のエンコードアルゴリズムの人気のある関数型言語(Haskell、ML)の両方の使用に興味があります
私はエキスパートではありませんが、99%です。ほとんどのMLフレーバーは、説明するクロージャーのバリエーションを使用していますが、最適化は行われている可能性があります。(おそらく古くなっている)視点については、これを参照してください。
Haskellは遅延評価のため、もう少し複雑な処理を行います。SpinelessTagless Graph Rewritingを使用します。
また、達成できる最も効率的な方法でも。
最も効率的なものは何ですか?すべての入力にわたって最も効率的な実装はないため、平均して効率的な実装が得られますが、それぞれが異なるシナリオで優れています。したがって、最も効率的または最も効率的であるという明確なランキングはありません。
ここには魔法はありません。関数を格納するには、何らかの方法でその自由な値を格納する必要があります。そうしないと、関数自体よりも少ない情報をエンコードします。おそらく、部分的な評価でいくつかの無料の値を最適化することができますが、それはパフォーマンスにリスクがあり、これが常に停止するように注意する必要があります。
そして、おそらくスペースの効率を上げるために、ある種の圧縮または巧妙なアルゴリズムを使用することができます。しかし、それは時間をスペースと交換するか、または一部のケースでは最適化し、他のケースでは速度を落とした状況にあります。
一般的なケースに合わせて最適化できますが、一般的なケースは、言語、アプリケーションの領域などによって変わる可能性があります。ビデオゲームで高速なコードの種類(数値の計算、大量の入力を伴うタイトなループ)は、おそらくコンパイラーの高速化(ツリートラバーサル、ワークリストなど)。
ボーナスポイント:関数エンコードされた整数をネイティブ整数(Cのshort、intなど)にマップするようなエンコードはありますか?可能ですか?
いいえ、できません。問題は、ラムダ計算では用語を内省できないことです。関数がChurch-numeralと同じ型の引数を取る場合、その数値の正確な定義を調べなくても、関数を呼び出すことができる必要があります。それがChurchエンコーディングでのことです。それらを使用して実行できる唯一のことはそれらを呼び出すことであり、これを使用して便利なすべてをシミュレートできますが、コストがかかりません。
さらに重要なことに、整数は可能なすべてのバイナリエンコーディングを占有します。したがって、ラムダが整数として表されている場合、チャーチ番号以外のラムダを表す方法はありません。または、ラムダが数値であるかどうかを示すフラグを導入しますが、必要な効率はウィンドウの外に出る可能性があります。
編集:これを書いて以来、高次関数を実装するための3番目のオプションである非機能化に気づきました。ここでは、switch
どのラムダ抽象化が関数として与えられたかに応じて、すべての関数呼び出しが大きなステートメントになります。ここでのトレードオフは、それがプログラム全体の変換であることです。事前にラムダ抽象化の完全なセットを用意する必要があるため、パーツを個別にコンパイルしてからこのようにリンクすることはできません。