ボックス化されていない型よりも上位の多態性


10

Hindley–Milnerに基づいて型推論を行い、デフォルトで型がボックス化されていない言語があります。主に存在型を扱うために、より高いランクのポリモーフィズムを追加したいと思います。

これらの型をチェックする方法は理解していると思いますが、コンパイルするときに何をすべきかわかりません。現在、私はC ++テンプレートのように特殊化を生成することによってポリモーフィックな定義をコンパイルし、ボックス化されていない値を処理できるようにしています。たとえば、の定義が与えられf<T>、プログラムがf<Int32>and のみを呼び出す場合、f<Char>それらの特殊化のみがコンパイルされたプログラムに表示されます。(今のところ、プログラム全体のコンパイルを想定しています。)

しかし、多態性関数を引数として渡すと、実行時に関数を選択できるため、適切な特殊化を静的に生成する方法がわかりません。ボックス化された表現を使用する以外に選択肢はありませんか?または問題を回避する方法はありますか?

私の最初の考えは、なんとかしてランクnの多型をランク1としてエンコードすることでしたが、構造論理の式は必ずしも通常の形をしているわけではないので、一般にそれが可能であるとは思いません。


別の方法は、関数の引数とメモリ内の単語がポインタであるビットマップを格納することにより、必要なボクシングの量を減らすことです。次に、多態性関数/構造体は、実際にはポインターまたはデータの任意の単語に対して多態性であり、構造体は最後のフィールド(多態性であっても)をインラインで格納できます。これらのビットマップをGCで使用して、非合計型のタグワードを不要にすることもできます。
fread2281 2017

@ fread2281:実際には、以前のバージョンの言語でそのようなことをしていました。現在、非合計タイプのタグを生成しておらず、GCもありません。それはニールKのアプローチとも互換性があると思います。
ジョンパーディ2017

回答:


6

私はこれについて少し考えました。主な問題は、一般に、多相型の値がどれほど大きいかわからないということです。この情報がない場合は、何らかの方法で入手する必要があります。モノモーフィゼーションは、ポリモーフィズムを特化することによってこの情報を取得します。ボクシングは、既知のサイズの表現にすべてを入れることにより、この情報を取得します。

3番目の選択肢は、この情報を種類別に追跡することです。基本的には、データサイズごとに異なる種類を導入することで、特定のサイズのすべてのタイプに対して多態性関数を定義できます。以下にそのようなシステムをスケッチします。

Kindsκ::=nType constructorsA::=a:κ.A|α|A×B|A+B|AB|refA|Pad(k)|μα:κ.A

ここでは、タイプの種類によって、メモリ内にオブジェクトを配置するのに必要な単語数がわかるという高いレベルの考え方があります。任意のサイズについて、その特定のサイズのすべてのタイプで多態性になるのは簡単です。すべてのタイプ(ポリモーフィックなタイプであっても)のサイズは既知であるため、コンパイルはCの場合より難しくありません。

分類規則はこの英語を数学に変換し、次のようになります:

α:nΓΓα:nΓ,α:nA:mΓα:n.A:m
ΓA:nΓB:mΓA×B:n+mΓA:nΓB:nΓA+B:n+1
ΓA:mΓB:nΓAB:1ΓA:nΓrefA:1
ΓPad(k):kΓ,α:nA:nΓμα:n.A:n

したがって、forall量指定子では、範囲を広げる種類を指定する必要があります。同様に、ペアリングはボックス化されていないペアタイプであり、メモリ内で隣にを配置するだけです(C構造体タイプのように)。Disjoint unionは、同じサイズの2つの値を取り、次に、弁別子タグの単語を追加します。関数はクロージャであり、通常、環境とコードのレコードへのポインタで表されます。A BA×BAB

参照は興味深いものです。ポインタは常に1語ですが、任意のサイズの値を指すことができます。これにより、プログラマー はボクシングによって任意のオブジェクトにポリモーフィズムを実装できますが、そうする必要ありません 。最後に、明示的なサイズが機能するようになったら、スペースを使用するが何もしないパディングタイプを導入すると便利です。(したがって、intと1組のintの素な結合を取得する場合は、最初のintにパディングを追加して、オブジェクトのレイアウトが均一になるようにする必要があります。)

再帰型には標準の形成規則がありますが、再帰発生は同じサイズでなければならないことに注意してください。これは、通常、それらをポインタに固定して、分類を機能させる必要があることを意味します。たとえば、リストのデータ型は次のように表すことができます

μα:1.ref(Pad(2)+int×α)

したがって、これは空のリスト値、または別のリンクされたリストへのポインターと整数のペアを指します。

このようなシステムの型チェックもそれほど難しくありません。私のICFP論文にあるJoshua Dunfieldのアルゴリズム、より高いランクのポリモーフィズムのための完全で簡単な双方向型チェックは、ほとんど変更なしでこのケースに適用されます。


クール、これは私のユースケースをきちんとカバーしていると思います。私は(GHCのような値の表現についての理由に種類を使用して認識していた*#)が、それをこのようにやって考えられていませんでした。ランクの高い量指定子を既知のサイズのタイプに制限するのは理にかなっているようで、実際のタイプを知らなくても、サイズごとの特殊化を静的に生成できると思います。さて、その紙をもう一度読む時間です。:)
Jon Purdy 2017

1

これは、「理論的なコンピューターサイエンス」の問題よりもコンパイルの問題に近いようです。そのため、他の場所に質問することをお勧めします。

一般的なケースでは、確かに、ボックス化された表現を使用する以外に解決策はないと思います。しかし、実際には、状況の詳細に応じて、さまざまな代替オプションがあることも期待しています。

たとえば、ボックス化されていない引数の低レベルの表現は、通常、整数または類似の、浮動小数点、またはポインターなど、非常に少数の選択肢に分類できます。したがって、関数の場合f<T>、おそらく3つの異なるボックス化されていない実装を生成する必要があるだけであり、ポリモーフィックな実装を3つの関数のタプルとして表すことができるため、TをInt32にインスタンス化することは、タプルの最初の要素を選択するだけです...


ご協力いただきありがとうございます。コンパイラーは高レベルの理論から低レベルのエンジニアリングに至るまで、どこに質問すればいいのか本当にわかりませんでしたが、私はこの辺の人々がいくつかのアイデアを持っていると考えました。ここでボクシングが実際に最も柔軟なアプローチであるように見えます。あなたの答えを読んでさらに考えた後、私が思いつくことができた他の唯一の合理的な解決策は、ある程度の柔軟性を放棄し、たとえば、多形引数を型パラメーターとして渡すなどして静的に知る必要があることです。それはずっと下のトレードオフです。:P
Jon Purdy 2017

4
OPの質問には、Damas-Hindley-Milnerがより高いランクの型で拡張されたときに型推論を行う方法など、完全に有効なTCS問題が含まれています。一般に、ランク2のポリモーフィズムには決定可能な型推論がありますが、ランクk> 2のタイプ推論は決定できません。ダマス・ヒンドリー・ミルナーの制限によってこれが変わるかどうかはわかりません。最後に、最近のコンパイラーが行うことのほぼすべてがTCSの一部である必要がありますが、通常、コンパイラーのインプリメンターは理論家よりも優れているため、そうではありません。
マーティンバーガー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.