Hindley –Milner ( HM )型システムは、パラメトリック多相性を持つラムダ計算の古典的な型システムです。Damas –MilnerまたはDamas–Hindley–Milnerとも呼ばれます。これは、J. Roger Hindley [ 1 ]によって最初に記述され、後にRobin Milner [ 2 ]によって再発見されました。Luis Damas は、博士論文でこの方法の詳細な形式的分析と証明を提供しました。[ 3 ] [ 4 ]
HM の注目すべき特性の中には、その完全性と、プログラマが提供する型注釈やその他のヒントなしに、与えられたプログラムの最も一般的な型を推論できる能力があります。アルゴリズム Wは、実際には効率的な型推論方法であり、理論的には複雑性が高いものの、大規模なコード ベースにうまく適用されています。[注 1 ] HM は関数型プログラミング言語で好んで使用されます。HM は、プログラミング言語MLの型システムの一部として最初に実装されました。それ以来、HM はさまざまな方法で拡張され、最も注目すべきはHaskellのような型クラス制約です。
型推論手法であるヒンドレー・ミルナーは、型指定のないスタイルで記述されたプログラムから、変数、式、関数の型を推論することができます。スコープに依存するため、ソースコードのごく一部から型を導出するだけでなく、プログラム全体やモジュール全体から型を導出することも可能です。また、パラメトリック型にも対応できるため、多くの関数型プログラミング言語の型システムの中核を成しています。この手法が最初に適用されたのは、MLプログラミング言語です。
その起源は、1958年にハスケル・カリーとロバート・フェイズによって考案された、単純型ラムダ計算の型推論アルゴリズムである。 1969年、J.ロジャー・ヒンドレーはこの研究を拡張し、彼らのアルゴリズムが常に最も一般的な型を推論することを証明した。1978年、ロビン・ミルナー[ 2 ]は、ヒンドレーの研究とは独立に、同等のアルゴリズムであるアルゴリズムWを提供した。1982年、ルイス・ダマス[ 4 ]は、ミルナーのアルゴリズムが完全であることを最終的に証明し、多相参照を持つシステムをサポートするように拡張した。
単純型ラムダ計算では、型Tは原子型定数または次の形式の関数型のいずれかである。このような型は単相型である。典型的な例としては、算術演算で使用される型が挙げられる。
これとは対照的に、型付けのないラムダ計算は型付けに全く依存せず、その多くの関数はあらゆる型の引数に意味のある形で適用できる。自明な例としては恒等関数が挙げられる。
これは、適用された値をそのまま返します。より単純な例としては、リストなどのパラメトリック型があります。
一般的に多相性とは、演算が複数の型の値を受け入れることを意味しますが、ここで使用されている多相性はパラメトリックです。文献には、多相性のパラメトリックな性質を強調する型スキームの表記法も見られます。さらに、定数は(量化された)型変数で型付けできます。たとえば、次の型スキームは、普遍的にを量化します。つまり、それらはすべての可能な場合に真である:
多相型は、変数の一貫した置換によって単相型になることができます。単相型のインスタンスの例は次のとおりです。
より一般的に言えば、型変数を含む型は多相型であり、型変数を含まない型は単相型である。
例えばPascal(1970年)やC(1972年)で使用されている型システムは単相型のみをサポートしていますが、HMはパラメトリック多相性を重視して設計されています。これらの言語の後継であるC++ (1985年)は、オブジェクト指向プログラミングに関連したサブタイピングやオーバーロードなど、異なるタイプの多相性に焦点を当てています。サブタイピングはHMとは互換性がありませんが、HaskellのHMベースの型システムでは、体系的なオーバーロードのバリアントが利用可能です。
単純型ラムダ計算の型推論を多相性へと拡張する場合、多相性型を式の型としてだけでなく、λに束縛された変数の型としても割り当てることが許容されるかどうかを決定する必要がある。これにより、以下の式において、汎用的な同一性型を変数「id」に割り当てることが可能になる。
(λ id . ... (id 3) ... (id "text") ... ) (λ x . x)
これを許容すると多相ラムダ計算が実現するが、このシステムにおける型推論は決定不可能である。[ 5 ]代わりに、HMは式に直接束縛される変数とより一般的なλ束縛変数を区別し、前者をlet束縛変数と呼び、多相型をこれらの変数にのみ割り当てることを可能にする。これによりlet多相が実現し、上記の例は次の形式をとる。
let id = λ x . x in ... (id 3) ... (id "text") ...
これは、'id' に多相型を付けることができます。示されているように、式構文は、let で束縛された変数を明示的にするために拡張され、型システムを制限して、let で束縛された変数のみが多相型を持つことを許可し、ラムダ抽象のパラメータは単相型を取得しなければならないようにすることで、型推論が決定可能になります。
この記事の残りの部分は以下の通りです。
推論システムの記述は、2つのアルゴリズムについても含め、全体を通して同じものが用いられており、HM法が提示される様々な形式を直接比較できるようにしている。
型システムは、式や型などの言語を規定する構文規則によって形式的に記述できます。ここで提示する構文は、表層文法ではなく深層文法を研究するために記述されており、構文の詳細の一部は未定のままになっているため、あまり形式的ではありません。このような記述形式は一般的です。これを基に、型付け規則を用いて式と型の関係を定義します。ここでも、前述と同様に、やや自由な形式が用いられています。
入力する式は、隣接する表に示すように、let式で拡張されたラムダ計算の式と全く同じです。括弧を使用して式を区別することができます。このアプリケーションは左拘束であり、抽象化やlet-in構文よりも強い拘束力を持ちます。
型は構文的にモノタイプとポリタイプの2つのグループに分けられます。[注2 ]
モノタイプは常に特定の型を指定します。モノタイプ構文的には用語として表現されます。
モノタイプの例としては、次のような型定数があります。またはパラメトリック型など後者のタイプは、例えば集合からの 型関数の適用例である。上付き文字は型パラメータの数を示します。型関数の完全なセットHMでは任意であるが、 [注3 ]少なくとも、関数の型。便宜上、中置記法で記述されることが多い。たとえば、整数を文字列にマッピングする関数の型は である。繰り返しになりますが、括弧は型式の曖昧さを解消するために使用できます。括弧は、右寄せである中置矢印よりも強い結合力を持ちます。
型変数はモノタイプとして認められます。モノタイプは、変数を除外し、基底項のみを許容する単相型と混同しないでください。
2つのモノタイプは、それらが同一の項を持つ場合に等しいとみなされる。
ポリタイプ(または型スキーム)は、0 個以上の for-all 量化子によって束縛される変数を含む型です。例:。
ポリタイプを持つ関数同じ型の任意の値をそれ自身にマッピングすることができ、恒等関数はこの型の値です。
別の例として、これは、すべての有限集合を整数にマッピングする関数の型です。集合の濃度を返す関数は、この型の値になります。
量指定子は最上位レベルでのみ使用できます。たとえば、型型の構文では除外されます。また、モノタイプはポリタイプに含まれるため、型は一般的に次の形式になります。、 どこそしては単一型です。
ポリタイプの等価性は、量化の順序を変更し、量化された変数の名前を変更することによって決まります(-変換)。さらに、モノタイプに存在しない量化された変数は削除できます。
まだばらばらな部分(構文式と型)を意味のある形で結びつけるには、3番目の部分、つまりコンテキストが必要です。構文的には、コンテキストはペアのリストです。割り当て、仮定、またはバインディングと呼ばれる各ペアは、値変数が型を持つこれら3つの要素を組み合わせると、フォームのタイピング判定が行われます。仮定の下では表現型を持つ。
あるタイプではシンボル量指定子は型変数を束縛しているかモノタイプにおいて変数は量化型と呼ばれ、量化型変数の出現ははバインド型変数と呼ばれ、バインドされていない型変数はすべては無料と呼ばれます。定量化に加えてポリタイプでは、型変数はコンテキスト内で出現することによっても束縛できますが、右辺では逆の効果があります。こうした変数は、そこでは型定数のように振る舞います。最後に、型変数は型付けの中で束縛されずに出現する可能性があり、その場合は暗黙的に全量化されます。
プログラミング言語では、束縛型変数と非束縛型変数の両方が存在することはやや珍しい。多くの場合、すべての型変数は暗黙的に全量化される。たとえば、Prologには自由変数を持つ節はない。同様に、Haskell [注 4 ]a -> aでは、すべての型変数が暗黙的に量化される。つまり、Haskell 型はここで。関連して、また非常に珍しいのは、右側の結合効果です。課題の。
通常、束縛型変数と非束縛型変数の混在は、式の中で自由変数を使用することから生じます。定数関数K =例を示します。モノタイプを持っています。多相性を強制するにはここに、タイプ自由型モノタイプ変数変数の型に由来する周囲の範囲に制約される。タイプ自由型変数を想像することができるタイプの拘束されるタイプのしかし、このようなスコープはHMでは表現できません。むしろ、バインディングはコンテキストによって実現されます。
多相性とは、同一の式が(おそらく無限に)多くの型を持つことができることを意味します。しかし、この型システムでは、これらの型は完全に無関係ではなく、パラメトリック多相性によって調整されています。
例えば、恒等式持つことができるその種類と同様に またはその他多数だが、この関数の最も一般的な型は 一方、他のものはより具体的であり、型パラメータ、つまり量化変数を別の型に一貫して置き換えることによって、一般的なものから導き出すことができる。反例は、置換が一貫性を欠いているため、成り立たない。
一貫した置換は、置換を適用することによって正式なものにすることができる。タイプの用語に書かれた例が示唆するように、置換は、型が多かれ少なかれ特別であることを示す順序と密接に関連しているだけでなく、置換の適用を可能にする全量化とも密接に関連しています。
正式には、HM では、タイプより一般的正式には定量化された変数が一貫して置き換えられ、サイドバーに示されているとおりです。この順序は、型システムの型定義の一部です。
前の例では、置換を適用すると結果として。
量化変数を単相型(基底型)に置き換えるのは簡単ですが、多相型に置き換える場合は、自由変数の存在によっていくつかの落とし穴があります。特に、非束縛変数は置き換えてはなりません。ここでは定数として扱われます。さらに、量化はトップレベルでのみ可能です。パラメトリック型に置き換える場合は、その量化子をリフトする必要があります。右側の表は、この規則を明確に示しています。
あるいは、量化子を持たない多型に対して、量化変数を別の記号セットで表す同等の表記法を考えてみましょう。このような表記法では、特殊化は、量化変数を単純に一貫性のある形で置き換えることに帰着します。
関係は半順序 で あり、それはその最小要素である。
型スキームの特殊化は順序の用途の一つですが、型システムにおいて順序はもう一つ重要な役割を担っています。多相性を伴う型推論では、式が持ちうるすべての型を要約するという課題に直面します。順序は、そのような要約が式の最も一般的な型として存在することを保証します。
上記で定義した型順序は型付けにも拡張できる。なぜなら、型付けの暗黙的な全量化により、一貫した置換が可能になるからである。
特殊化規則とは異なり、これは定義の一部ではなく、暗黙の全量化と同様に、次に定義される型規則の結果です。型付け内の自由型変数は、可能な改良のためのプレースホルダーとして機能します。環境の右辺の自由型変数への束縛効果は、専門化ルールにおいてそれらの置き換えを禁止する理由は、置き換えが一貫性を持ち、型付け全体を含める必要があるという点にある。
この記事では、4つの異なるルールセットについて説明します。
HMの構文は、型付けを判断として用いることで、形式体系の本体を構成する推論規則の構文へと引き継がれる。各規則は、どのような前提からどのような結論が導き出せるかを定義する。判断に加えて、上述の追加条件も前提として用いられる場合がある。
規則を用いた証明は、すべての前提が結論の前に列挙されるような一連の判断です。以下の例は、証明の可能な形式を示しています。左から右へ、各行は結論、適用された規則と前提について、前提が判断である場合は前の行(番号)を参照するか、述語を明示することによって示します。
サイドボックスには、HM型システムの推論ルールが示されています。ルールは大きく2つのグループに分けられます。
最初の4つのルール(変数または関数へのアクセス)(アプリケーション、つまりパラメータが1つの関数呼び出し)(抽象化、つまり関数宣言)(変数宣言)は構文を中心に据え、各式形式ごとに1つの規則を示します。各式を分解し、その部分式を証明し、最後に前提にある個々の型を結論にある型と組み合わせるため、その意味は一目瞭然です。
2番目のグループは残りの2つのルールによって構成されるそしてそれらは型の特殊化と一般化を扱います。ルールは上記の専門化に関するセクションから明らかであるはずです。これは前者を補完するもので、逆方向に作用します。つまり、一般化を可能にし、コンテキストで束縛されていない単一型変数を定量化することができます。
以下の2つの例は、ルールシステムの実際の動作を示しています。式と型の両方が指定されているため、これらはルールの型チェックの例です。
例:証明どこと書くことができる
例:一般化を示すために、 以下に示します。
すぐには見えないが、ルールセットは、ルール内で単一型と多型をわずかに異なる方法で使用することにより、どのような状況下で型が一般化されるかされないかを規定する規則をエンコードしている。そして覚えておいてくださいそしてそれぞれ多型と単型を表す。
ルールでは関数のパラメータの値変数前提を通して単相型でコンテキストに追加されます規則では 変数は多形形式で環境に入るどちらの場合も、この文脈では、割り当て内の自由変数に対する一般化ルールの使用が禁止され、この規則はパラメータの型を強制します。で-式は単相のままですが、let式では変数を多相的に導入することができ、特殊化が可能になります。
この規制の結果、パラメータがは単型位置にあり、型を持つ、 なぜならlet式に導入されているため、多相として扱われます。
一般化規則も詳しく見てみる価値がある。ここでは、前提に暗黙的に含まれる全量化が単に右側に移動されます結論では、明示的な全称量化子によって束縛される。これは可能である。文脈上、自由形式は存在しない。繰り返しになるが、これは一般化規則をもっともらしく見せるものの、実際には結果ではない。それどころか、一般化規則はHMの型システムの定義の一部であり、暗黙の全量化はその結果である。
HMの推論システムが利用可能になった今、アルゴリズムを提示し、規則に照らして検証することができる。あるいは、規則がどのように相互作用し、証明がどのように形成されるかを詳しく調べることで、アルゴリズムを導出することも可能かもしれない。本稿の残りの部分では、型付けを証明する際に可能な決定に焦点を当て、この方法を検討する。
証明の中で、決定が全く不可能な点を分離すると、構文を中心とした最初の規則群は選択肢を残しません。なぜなら、各構文規則には一意の型付け規則が対応し、それが証明の一部を決定するからです。一方、これらの固定部分の結論と前提の間には、そして 起こり得る。このような連鎖は、証明の結論と最上位式の規則の間にも存在し得る。すべての証明は、このように概略的に示された形状を持たなければならない。
証明におけるルール選択の唯一の選択肢は そして連鎖的な証明形式は、このような連鎖が不要になるような、より精密な証明が可能かどうかという疑問を提起する。実際、これは可能であり、そのような規則を持たない規則体系の変種につながる。
現代における人文管理の扱いでは、クレメント[ 6 ]による純粋に構文指向のルールシステムを 中間段階として用いる。このシステムでは、特殊化は元のルールの直後に配置される。ルールに統合され、一般化はルール。そこでは、関数を導入することで、常に最も一般的な型を生成するように一般化も決定されます。これは、バインドされていないすべてのモノタイプ変数を定量化します。。
正式には、この新しいルールシステムがオリジナルと同等示さなければならないのはこれは、2つの部分証明に分解される。
規則を分解することで一貫性が確認できるそして の証明におそらく、不完全である、示すことができないで例えば、 完全性のわずかに弱いバージョンは証明可能である [ 7 ] 。すなわち、
つまり、式の主要な型を導出できる。最終的に証明を一般化することができる。
比較するそして今では、すべての規則の判断において、単一型のみが現れます。さらに、演繹システムを用いたあらゆる可能な証明の形状は、式の形状と同一になります(どちらも木として見た場合)。したがって、式は証明の形状を完全に決定します。形状は、以下のすべての規則に関して決定される可能性が高いそしてこれにより、他のノード間に任意の長さのブランチ(チェーン)を構築することが可能になります。
証明の構造がわかったので、型推論アルゴリズムの定式化にかなり近づいたと言える。与えられた式に対する証明はすべて同じ構造を持つはずなので、証明の判断における単一型は未決定であると仮定し、それらをどのように決定するかを検討することができる。
ここで、置換(特殊化)順序が重要になります。一見すると、局所的に型を決定することはできませんが、証明ツリーをたどる際に順序を利用して型を洗練できると期待されています。さらに、結果として得られるアルゴリズムは推論方法となるため、どの前提においても型は可能な限り最良のものとして決定されると仮定します。そして実際、規則を見ると、提案する:
ユニオンファインドアルゴリズムを簡単にまとめると、証明に含まれるすべての型の集合が与えられた場合、ユニオン手続きによってそれらを同値類にグループ化し、ファインド手続き によって各同値類の代表を選択することができます。ここで「手続き」という言葉を副作用という意味で強調すると、効果的なアルゴリズムを準備するために、明らかに論理の領域から離れていることがわかります。aとbの両方が型変数である場合、代表はどちらか一方になりますが、変数と項を結合する際には、項が代表になります。union-findの実装を前提とすると、2つのモノタイプの結合は次のように定式化できます。
unify(ta, tb): ta = find(ta) tb = find(tb) ta、tb の両方が D p1..pn の形式で、D、n が同一である場合、対応するi番目のパラメータ ごと に unify(ta[i]、tb[i]) を実行する。そうでない場合、 ta、tb の少なくとも 1 つが型変数である場合、 union(ta, tb) それ以外の場合は 「型が一致しません」というエラーが表示されます。
推論アルゴリズムの概略がわかったので、次のセクションでより正式な説明を行います。これは、Milner [ 2 ]の 370 ページ以降でアルゴリズム J として説明されています。
アルゴリズム J の提示は、副作用を含みながらも直接比較を可能にするため、論理規則の表記法の誤用である。同時に効率的な実装を表現している。ルールでは、パラメータを持つ手順が指定される。降伏結論では、前提の実行は左から右へと進む。
手順多型を特殊化する用語をコピーし、バインドされた型変数を新しいモノタイプ変数に一貫して置き換えることによって。' は新しいモノタイプ変数を生成します。おそらく、不要なキャプチャを避けるために、量化のための新しい変数を導入する型をコピーする必要があります。全体として、アルゴリズムは常に最も一般的な選択を行い、特殊化は単一化に任せることで進行し、単一化自体が最も一般的な結果を生成します。上記のように、最終結果は一般化する必要がある最終的には、与えられた式に対して最も一般的な型を得るため。
アルゴリズムで使用される手順のコストがほぼ O(1) であるため、アルゴリズム全体のコストは、型推論の対象となる式のサイズに対してほぼ線形になります。これは、終了性に関して決定不能ではないにしても、NP 困難となることが多かった他の多くの型推論アルゴリズムの導出の試みとは大きく異なります。したがって、 HM は、最も優れた完全情報型チェックアルゴリズムと同等の性能を発揮します。ここでの型チェックとは、アルゴリズムが証明を見つける必要はなく、与えられた証明を検証するだけでよいことを意味します。
コンテキスト内の型変数の束縛を維持して計算を可能にする必要があるため、効率はわずかに低下します。また、再帰型の構築中に発生チェックを有効にして、その一例は型は HM を使用して導出することはできません。実際には、型は小さな項にすぎず、拡張構造を構築しません。したがって、複雑性分析では、型の比較を定数として扱い、O(1) のコストを維持できます。
前節では、アルゴリズムの概要を説明する際に、メタ論理的議論を用いてその証明を示唆した。これにより効率的なアルゴリズムJが得られるものの、このアルゴリズムが意味論的基盤となる演繹システムDまたはSを適切に反映しているかどうかは明らかではない。
上記の議論で最も重要な点は、コンテキストによって束縛される単一型変数の精緻化です。たとえば、アルゴリズムは推論中にコンテキストを大胆に変更します。なぜなら、パラメーターのコンテキストにモノタイプ変数が追加されたからである。後で洗練する必要があるアプリケーションを処理する際に問題となるのは、推論規則がそのような改良を許容しないことである。改良された型を単一型変数の代わりに早期に追加できたはずだと主張するのは、せいぜい便宜的な言い訳に過ぎない。
形式的に満足のいく議論にたどり着くための鍵は、適切な文脈を洗練の中に組み込むことである。形式的には、型付けは自由型変数の置換と互換性がある。
自由変数を洗練するということは、型全体を洗練することを意味する。
そこから、アルゴリズム J の証明によりアルゴリズム W が得られ、これは手順によって課される副作用のみを生じさせる。置換によってその直列構成を表現することで明示的になる サイドバーのアルゴリズム W の提示では、斜体で示された操作セットに副作用がまだ使用されていますが、これらは新しいシンボルを生成することに限定されています。判断の形式は、これは、コンテキストと式をパラメータとして持つ関数を表し、置換とともに単一型を生成します。副作用のないバージョンです最も一般的な統一子である置換を生成する。
アルゴリズムWは通常HMアルゴリズムと考えられており、文献ではルールシステムの直後に提示されることが多いが、その目的はミルナー[ 2 ]によって369ページで次のように説明されている。
彼はWの方が複雑で効率が悪いと考えていたが、Jよりも先に自身の論文でWを紹介した。副作用が利用できない場合や望ましくない場合には、Wには利点がある。また、Wは完全性を証明するためにも必要であり、彼はそれを健全性証明に組み込んでいる。
証明義務を定式化する前に、規則体系DとSと提示されたアルゴリズムとの間の相違点を強調する必要がある。
上記の開発では、モノタイプを「オープン」な証明変数として誤用した側面があったものの、本来のモノタイプ変数が損なわれる可能性は、新たな変数を導入して最善を尽くすことで回避された。しかし、落とし穴がある。これらの新たな変数は「そのように認識される」という約束があったにもかかわらず、このアルゴリズムはその約束を果たしていないのだ。
文脈を持つ表現 どちらも入力できませんまたはしかし、アルゴリズムは次のようなタイプを生成しますここで、Wはさらに置換を提供するつまり、このアルゴリズムはすべての型エラーを検出できないということです。この欠点は、証明変数と単一型変数をより注意深く区別することで簡単に修正できます。
著者らはこの問題を十分に認識していたが、修正しないことに決めた。これには実用的な理由があったと考えられる。型推論をより適切に実装すれば、アルゴリズムは抽象モノタイプを扱えるようになるが、既存のコンテキスト内のどの項目にも自由変数がないという想定されるアプリケーションでは、それらは必要なかった。この観点から、不要な複雑さを排除し、より単純なアルゴリズムを採用した。残る欠点は、ルールシステムに関するアルゴリズムの証明が汎用性に欠け、特定のコンテキストに対してのみ証明できるということである。付随条件として。
完全性義務における付随条件は、推論によって複数の型が生成される可能性がある一方で、アルゴリズムは常に単一の型を生成するという点に対処するものである。同時に、この付随条件は、推論された型が実際に最も一般的な型であることを要求している。
義務を適切に証明するには、まず義務を強化して置換補題を活性化し、置換をスレッド化する必要がある。を通してそしてそこからは、式に関する帰納法によって証明を行う。
もう一つの証明義務は、置換補題そのもの、すなわち型付けの置換であり、これによって最終的に全量化が確立される。後者は、そのような構文が存在しないため、形式的に証明することはできない。
プログラミングを実用的にするためには、再帰関数が必要です。ラムダ計算の重要な特性は、再帰定義が直接利用できないものの、不動点コンビネータで表現できる点です。しかし、不動点コンビネータは、後述するようにシステムに深刻な影響を与えることなく、型付きラムダ計算で定式化することはできません。
元の論文[ 4 ]では、再帰はコンビネータによって実現できることが示されている。 したがって、考えられる再帰的な定義は次のように定式化できる 。 ::={\mathtt {let}}\ v={\mathit {fix}}(\lambda v.e_{1})\ {\mathtt {in}}\ e_{2}} 。
あるいは、式構文の拡張と追加の型付け規則を用いることも可能です。
どこ
基本的に合併するそして再帰的に定義された変数を、その左側に現れる単一型位置に含めながらしかし、その右側には多型として存在する。
上記は単純明快だが、それには代償が伴う。
型理論はラムダ計算と計算および論理を結びつける。上記の簡単な変更は、両方に影響を与える。
オーバーロードとは、同じ名前で異なる関数を定義して使用できることを意味します。ほとんどのプログラミング言語では、少なくとも組み込みの算術演算(+、<など)のオーバーロードが提供されており、プログラマーは、異なる数値型(例えば、または)であっても、同じ形式で算術式を記述できますint。real同じ式内でこれらの異なる型が混在すると暗黙的な型変換も必要となるため、特にこれらの演算のオーバーロードは、多くの場合、プログラミング言語自体に組み込まれています。一部の言語では、この機能が一般化され、ユーザーが利用できるようになっています(例:C++)。
関数型プログラミングでは、型チェックと型推論の両方における計算コストのため、アドホックなオーバーロードは避けられてきましたが、オーバーロードを体系化する手段として、形式と命名規則の両面でオブジェクト指向プログラミングに似たものが導入されました。ただし、これは1つ上のレベルで機能します。この体系における「インスタンス」はオブジェクト(つまり値レベル)ではなく、型です。序論で述べたクイックソートの例では、順序にオーバーロードが使用されており、Haskellでは次の型注釈が付けられています。
quickSort :: Ord a => [ a ] -> [ a ]ここで、型はa多相的であるだけでなく、Ord順序述語を提供し<、>=関数本体で使用される何らかの型クラスのインスタンスであるように制限されています。これらの述語の適切な実装は、オーバーロードされた関数 quickSort の単一の実装を提供するより具体的な型に対してクイックソートが使用されるとすぐに、追加のパラメータとしてクイックソートに渡されます。
「クラス」は引数として単一の型しか受け付けないため、結果として得られる型システムは推論機能を提供できます。さらに、型クラスには何らかのオーバーロード順序を持たせることができ、クラスを格子状に配置することが可能です。
パラメトリック多相性とは、型自体が適切な値であるかのようにパラメータとして渡されることを意味します。適切な関数への引数として渡されるだけでなく、「パラメトリック」型定数のように「型関数」にも渡されるため、型自体をより適切に型付けする方法が問われます。高階型は、さらに表現力豊かな型システムを作成するために使用されます。
メタ型が存在する場合、単一化はもはや決定不可能となり、この程度の一般性では型推論は不可能となる。さらに、自身を型として含むすべての型の型を仮定すると、すべての集合の集合の場合と同様にパラドックスに陥るため、抽象化のレベルを段階的に上げていく必要がある。一段階上の二階ラムダ計算の研究により、この一般性では型推論が決定不可能であることが示された。
Haskell では、 kindという上位レベルが導入されています。標準 Haskell では、kind は推論され、型コンストラクタの引数の数を記述する以外にはほとんど使用されません。たとえば、リスト型コンストラクタは、型 (その要素の型) を別の型 (その要素を含むリストの型) にマッピングするものと考えられています。表記上は、次のように表されます。依存型システムの機能を模倣するために型を拡張する言語拡張機能が利用可能です。[ 8 ]
サブタイピングと型推論を組み合わせようとする試みは、かなりのフラストレーションを引き起こしてきました。サブタイピング制約(型等価制約とは対照的に)を蓄積して伝播させることは容易であり、結果として得られる制約を推論された型スキームの一部にすることができます。たとえば、、 どこ型変数に対する制約ですしかし、このアプローチでは型変数が積極的に統一されないため、多くの役に立たない型変数と制約を含む、大きくて扱いにくい型付けスキームが生成され、読みにくく理解しにくくなる傾向がある。そのため、非決定性有限オートマトン(NFA) の簡略化 (推論された再帰型が存在する場合に有用) と同様の手法を使用して、このような型付けスキームとその制約を簡略化するためにかなりの努力が払われた。[ 9 ] 最近では、Dolan と Mycroft [ 10 ] が型付けスキームの簡略化と NFA の簡略化の関係を形式化し、サブタイピングの形式化に対する代数的アプローチにより、ML ライクな言語 (MLsub と呼ばれる) のコンパクトな主型付けスキームを生成できることを示した。注目すべきは、彼らが提案した型付けスキームでは、明示的な制約の代わりに、制限された形式のユニオン型とインターセクション型が使用されたことである。パローは後に[ 11 ] 、この代数的な定式化はアルゴリズムWに似た比較的単純なアルゴリズムと同等であり、和集合型と積集合型の使用は必須ではないと主張した。
一方、オブジェクト指向プログラミング言語のコンテキストでは、型推論はより困難であることがわかっています。これは、オブジェクトのメソッドがSystem F(型推論が決定不能)スタイルの第一級多相性を必要とする傾向があること、およびF境界多相性などの機能があるためです。したがって、 Cardelliのシステムのように、サブタイピングによってオブジェクト指向プログラミングを可能にする型システム[ 12 ]はHMスタイルの型推論をサポートしていません。
行多相性は、構造レコードなどの言語機能をサポートするためにサブタイピングの代替として使用できます。[ 13 ] このスタイルの多相性は、型制約の方向性の欠如に対処するために厳密に必要な以上の多相性を必要とするなど、いくつかの点でサブタイピングよりも柔軟性に劣りますが、標準的な HM アルゴリズムと非常に簡単に統合できるという利点があります。
{{cite journal}}:ジャーナルを引用するには|journal=(ヘルプ)