Hindley-Milnerのどの部分を理解していないのですか?


851

私はかつて不滅の言葉をフィーチャーした販売用のTシャツがあったことを誓います:


のどの部分

Hindley-Milner

分かりませか?


私の場合、答えは...すべてです!

特に、Haskellの論文ではこのような表記がよく見られますが、その意味がわかりません。それがどういう数学の分野になるのか私にはわからない。

もちろんギリシャ語のアルファベットの文字と「∉」などの記号を認識します(これは通常、何かがセットの要素ではないことを意味します)。

一方、「⊢」は今まで見たことがありませんWikipediaは「パーティション」を意味する可能性があると主張しています)。ここでのビンキュラムの使用についてもよく知りません。(通常は、分数を表し、それはしません表示され、ここでケースのように。)

このシンボルの海が何を意味するのかを理解するためにどこから始めればよいかを誰かが少なくとも教えてくれれば、それは役に立ちます。


8
あなたがいる場合されているアルゴリズムの良い説明を探して、私がこれまでに発見したことを最もよくシュライラン・クリシュナマーティさんの章30であるプログラミング言語:アプリケーションと解釈(CCライセンスを取得!)。
laslowh 2013

2
@laslowhありがとうございます!私はそれを読んでいます。新しいバージョン:cs.brown.edu/courses/cs173/2012/book/book.pdf
SnowOnion

回答:


652
  • 水平バー「[上方]があることを意味意味【下に」。
  • [上記]に複数の式がある場合は、それらをまとめて検討します。[下記]を保証するには、[上記]のすべてがtrueである必要があります。
  • :タイプは意味します
  • 手段はにあります。(同様に、「ではない」を意味します。)
  • Γ通常、環境またはコンテキストを参照するために使用されます。この場合、識別子とその型を組み合わせた、型注釈のセットと考えることができます。したがってx : σ ∈ Γ、環境Γxはタイプがあるという事実が含まれていることを意味しますσ
  • 証明または決定として読み取ることができます。Γ ⊢ x : σは、環境がtypeをΓ決定することを意味します。xσ
  • ,は、特定の追加の前提条件を環境に含める方法ですΓ
    したがって、Γ, x : τ ⊢ e : τ'その環境を意味しΓ追加、上書き前提とx種類がありτ、それが証明しているeタイプがありますτ'

要求どおり:演算子の優先順位、最高から最低:

  • などの言語固有の中置とmixfix演算子、λ x . e∀ α . σ、及びτ → τ'let x = e0 in e1機能アプリケーションのための、および空白。
  • :
  • そして
  • , (左関連)
  • 複数の命題を分離する空白(連想)
  • 水平バー

19
演算子の優先規則は何ですか?
Randomblue 2013

:そしてセットが要素を含んでおり、種類はある意味で、値が含まれている-彼らは一つのことは別のものに含まれていることを意味するという点で、非常によく似ています。決定的な違いはx ∈ S、セットがS文字通り要素を含んxでいるΓ ⊢ x : Tことを意味しxますがT、コンテキスト内の生息タイプに推定できることを意味しますΓ。これを考慮すると、Varルールは次のようになります。»xが文字通りコンテキストに含まれている場合、(自明なことに)xから推測できます«。
David

@Randomblue括弧をすべての場所に追加することで、シンボルの優先順位を明示しました。たとえば(Γ,(x:τ))⊢(x:σ)overleaf.com
read / ddmnkzjtnqbd

327

この構文は複雑に見えるかもしれませんが、実際にはかなり単純です。基本的な考え方は形式的な論理から来ています。式全体が含意されており、上半分は仮定であり、下半分は結果です。つまり、上の式が真であることがわかっている場合は、下の式も真であると結論付けることができます。

シンボル

覚えておくべきもう1つのことは、一部の文字には従来の意味があるということです。特に、Γはあなたがいる「コンテキスト」、つまりあなたが見た他のタイプのものが何であるかを表します。したがって、のようなものΓ ⊢ ...は、「...のすべての式のタイプを知っているときの式」を意味しΓます。

シンボルは、基本的に、あなたが何かを証明できることを意味します。だから、Γ ⊢ ...私は証明することができます」との声明である...コンテキストでは、Γこれらの記述は、タイプの判断と呼ばれています。

もう1つ覚えておかなければならないのは、数学では、MLやScalaと同じように、型があるx : σということです。Haskellと同じように読むことができます。xσx :: σ

各ルールの意味

つまり、これを知っていると、最初の式が理解しやすくなります。つまり、それがわかっているx : σ ∈ Γ(つまり、あるコンテキストにx何らかの型σがあるΓ)場合、それがわかっていますΓ ⊢ x : σ(つまり、in Γxは型がありますσ)。だから、本当に、これはあなたに何か超興味深いことを言っているのではありません。コンテキストの使用方法を伝えるだけです。

他のルールも簡単です。たとえば、を取り[App]ます。この規則は、二つの条件があります:e₀いくつかのタイプから関数であるτいくつかのタイプへτ'e₁型の値ですτ。これで、に適用e₀することでどのタイプが得られるかがわかりますe₁!うまくいけば、これは驚きではありません:)。

次のルールには、いくつかの新しい構文があります。特に、Γ, x : τ構成されているコンテキストΓと判断を意味しますx : τ。我々は変数があることを知っているのであれば、xの種類がありτ、式がe型を持ってτ'、我々はまた、かかる機能の種類を知っているxとリターンをe。これは、関数が取る型と関数が返す型がわかっている場合の対処方法を示しているだけなので、驚くことではありません。

次は、letステートメントの処理方法を説明するだけです。あなたには、いくつかの表現があることがわかっている場合はe₁型を持つτ限りとしてxのタイプがありσ、その後、letローカルにバインドする表現x型の値にはσなりますe₁タイプを持っていますτ。実際、これはletステートメントが本質的に新しいバインディングでコンテキストを拡張できることを示しています—まさにそれが何をするかletです!

[Inst]ルールは、サブタイピングを扱っています。typeの値がσ'あり、それがσ部分的な順序関係を表す)のサブタイプである場合、その式 typeであることを示していσます。

最後のルールは、型の一般化を扱います。余談ですが、自由変数とは、式の中のletステートメントやラムダによって導入されない変数です。この式は、コンテキストからのフリー変数の値に依存するようになりました。ルールは、コンテキスト内の何にも「フリー」でαない変数がある場合、型がわかっている式はe : σ任意の値に対してそのタイプになりますα

ルールの使い方

では、シンボルを理解したところで、これらのルールをどのように使用しますか?これらのルールを使用して、さまざまな値のタイプを把握できます。これを行うには、式を見て(たとえばf x y)、ステートメントに一致する結論(下部)を持つルールを見つけます。あなたがあなたの「目標」を見つけようとしているものを呼びましょう。この場合、末尾がであるルールを確認しますe₀ e₁。これを見つけたら、このルールの境界より上のすべてを証明するルールを見つける必要があります。これらは通常、部分式のタイプに対応しているため、基本的に式の一部を再帰的に処理します。証明ツリーが完成するまでこれを行うだけで、表現のタイプの証明が得られます。

したがって、これらすべてのルールは、式のタイプを理解する方法を正確に(そして通常の数学的に詳細な説明:Pで)指定することです。

さて、これまでにPrologを使用したことがあれば、これはおなじみのはずです。つまり、人間のPrologインタプリタのように証明ツリーを本質的に計算しています。プロローグが「ロジックプログラミング」と呼ばれるのには理由があります!私がHM推論アルゴリズムを紹介された最初の方法は、Prologに実装することであったため、これも重要です。これは実際には驚くほど簡単で、何が起こっているのかを明確にします。ぜひお試しください。

注:私はおそらくこの説明でいくつかの間違いをしたので、誰かがそれを指摘してくれればそれが好きになるでしょう。私は実際に数週間でクラスでこれをカバーするので、私はそれからより自信があります:P。


5
\ alphaはnon-free型の変数であり、通常の変数ではありません。したがって、一般化規則を説明するには、さらに多くのことを説明する必要があります。
nponeccop 2012

2
@nponeccop:うーん、良い点。私は実際にその特定のルールを見たことがない。適切に説明してくれませんか。
Tikhon Jelvis 2012

8
@TikhonJelvis:それは(と仮定すると、あなたが一般化することができ、実際にはかなり簡単ですΓ = {x : τ}λy.x : σ → τには∀ σ. σ → τ、なくする∀ τ. σ → τため、τ中に自由変数ですΓHMに関するウィキペディアの記事は、それをかなりうまく説明しています。
Vitus

7
に関連する答えの部分は[Inst]少し不正確だと思います。これはこれまでのところ私の理解ですが、[Inst]および[Gen]ルールのシグマは型を参照するのではなく、型スキームを参照します。したがって、OO言語からわかるように、演算子はサブタイピングとは関係のない部分的な順序付けです。これは、などの多態的な値に関連していid = λx. xます。このような関数の完全な構文はですid = ∀x. λx. x。今、私たちは明らかに持つことができるid2 = ∀xy. λx. x場所、y使用されていませんが。次にid2 ⊑ id、それは[Inst]ルールが言うことです。
Ionuț G. Stan 2015

71

誰かがこのシンボルの海の意味を理解するためにどこから始めればよいかを少なくとも教えてもらえたら

判断と導出による論理のスタイルについては、「プログラミング言語の実用的な基礎」、第2章と第3章を参照してください。本全体がAmazonで入手できるようになりました。

第2章

帰納的定義

帰納的定義は、プログラミング言語の研究に不可欠なツールです。この章では、帰納的定義の基本的なフレームワークを開発し、それらの使用例をいくつか示します。帰納的定義は、さまざまな形式の判断またはアサーションを導出するための一連のルールで構成されています。判断は、指定されたソートの1つ以上の構文オブジェクトに関するステートメントです。ルールは、判断の有効性のために必要かつ十分な条件を指定し、その意味を完全に決定します。

2.1判決

まず、判断の概念、または構文オブジェクトに関する主張から始めます。私たちは、次のような例を含む、さまざまな形態の判断を利用します。

  • n natnは自然数
  • n = n1 + n2nn1n2の合計です
  • τ タイプ - τがタイプです
  • eτ—eのタイプはτ
  • 電子V -表現eが値を持つVを

判決は、1つまたは複数の構文オブジェクトがプロパティを持っているか、または互いに何らかの関係にあると述べています。プロパティまたは関係自体は判断フォームと呼ばれ、1 つまたは複数のオブジェクトがそのプロパティを持っている、またはその関係にあるという判断は、その判断フォームのインスタンスと呼ばれます。判定フォームも呼ばれる述語、およびインスタンスを構成するオブジェクトは、ある被験者。私たちは、書き込みJと主張判断のためのJがで保持しています。判断の主題を強調することが重要ではない場合(テキストはここで途切れる)


53

Hindley-Milnerのルールを理解するにはどうすればよいですか?

Hindley-Milnerは、後続の計算(自然な演繹ではない)の形式の一連のルールであり、明示的な型宣言なしでプログラムの構造からプログラムの(最も一般的な)型を推定できることを示します。

記号と表記

まず、記号について説明し、演算子の優先順位について説明します

  • 𝑥は識別子(非公式には変数名)です。
  • はのタイプです(非公式には、インスタンス、または「is-a」)。
  • 𝜎(シグマ)は、変数または関数の式です。
  • したがって、𝑥:𝜎は「 " is -a 𝜎」と読み取られます
  • ∈は「の要素」であることを意味します
  • 𝚪(ガンマ)は環境です。
  • (アサーション記号)は、アサート(または証明しますが、状況に応じて「アサート」の方が読み取りが良い)を意味します。
  • ⊦Γ 𝑥 σ、読み取られる"Γは、その𝑥をアサートは、σ "
  • 𝑒は、型の実際のインスタンス(要素)ですσ
  • 𝜏(タウ)はタイプ:基本、変数(𝛼)、機能𝜏→𝜏 'または製品𝜏×𝜏'(製品はここでは使用されません)
  • 𝜏→𝜏 'は関数型であり、 𝜏𝜏'は潜在的に異なる型です。
  • λ𝑥.𝑒手段λ(ラムダ)は、引数を取る匿名関数で𝑥、発現、返し𝑒を

  • 聞かせて 𝑥 =𝑒₀ 𝑒₁式の手段、𝑒₁、代替𝑒₀どこ𝑥が表示されます。

  • は、前の要素が後者の要素のサブタイプ(非公式にはサブクラス)であることを意味します。

  • 𝛼は型変数です。
  • α.σはタイプ、∀(すべてのための)引数の変数であり、 α、帰国σ式を
  • ∉free (𝚪)は、外部コンテキストで定義された𝚪の自由型変数の要素ではないことを意味します。(バインドされた変数は置換可能です。)

線より上のすべてが前提であり、下のすべてが結論です(Martin-Löfによる

優先順位、例による

ルールからより複雑な例をいくつか取り、優先順位を示す冗長な括弧を挿入しました:

  • 𝑥:σ ∈Γ書くことができます(𝑥:σ) ∈Γ
  • Γ⊦ 𝑥 σは Γを書くことができ⊦(𝑥 σ

  • Γは⊦ 𝑥 =𝑒₀ 𝑒₁τは、 ((⊦等価Γある𝑥 =𝑒₀ 𝑒₁):τ

  • Γ⊦ λ𝑥.𝑒τ→τ 'である等価Γ⊦((λ𝑥.𝑒):(τ→τ' ))

次に、アサーションステートメントと他の前提条件を区切る大きなスペースは、そのような前提条件のセットを示し、最後に前提と結論を区切る水平線が優先順位の終わりを示します。

ルール

ここに続くのは、規則の英語の解釈であり、それぞれに緩やかな言い直しと説明が続きます。

変数

VAR論理図

𝑥がtype(シグマ)のタイプ、Given(ガンマ)の要素で
あるとすると、Givenは𝑥がaであると断定します。

言い換えると、𝚪は、𝜎が𝜎の型であるため、𝑥がtypeの型であることを知っています。

これは基本的にトートロジーです。識別子名は変数または関数です。

機能アプリケーション

APPロジック図

与えられた𝚪アサート𝑒₀は関数型であり、𝚪アサート𝑒₁は𝜏
結論であるluアプライする関数applyingを𝑒₁にアサートする𝑒₁は型𝜏である

ルールを言い換えると、関数applicationはタイプ𝜏 'を返すことがわかっています。これは、関数がタイプ𝜏→𝜏'を持ち、タイプargumentの引数を取得するためです。

つまり、関数が型を返すことがわかっていて、それを引数に適用すると、結果は、その関数が返す型のインスタンスになります。

関数の抽象化

ABS論理図

タイプ𝚪の𝚪とGivenが、𝑒がタイプであることを表明し、𝜏 'が
匿名関数を表明したと結論付け、𝑥が式を返す𝜆の𝜆、タイプtype→𝜏'を𝑒

繰り返しますが、𝑥を受け取り、式returnsを返す関数がある場合、type(a 𝜏)は𝑒が𝜏 'であると断言するため、it→𝜏'型であることがわかります。

𝑥がタイプtypeであり、したがって式𝑒がタイプ𝜏 'であることがわかっている場合、式𝑥を返すofの関数はタイプ𝜏→𝜏'です。

変数宣言をしましょう

LET論理図

Γは式σの、𝑒₀をアサートし、所与及び Γと𝑥は、タイプσのタイプの𝑒₁をτアサート
Γがアサート結論let𝑥=𝑒₀ in型τの𝑒₁を

大まかに言うと、𝑒₀は𝑒₁(a 𝜏)の𝑒₀にバインドされています。これは、𝑒₀が𝜎であり、𝑥が𝑒₁が𝜏であることを表明する𝑥だからです。

つまり、a(変数または関数)である式beと、名前𝑥、また𝜎、およびタイプ𝑒₁の式haveがある場合、𝜏の代わりにsubstituteを𝑒₀に置き換えることができますofの。

インスタンス化

INST論理図

Givenがタイプ𝜎 'のアサート𝚪であり、𝜎'が𝜎のサブタイプである
とすると、結論𝚪アサート𝑒はタイプofである

式𝑒は親タイプofです。式𝜎はサブタイプ𝜎 'であり、𝜎は𝜎'の親タイプであるためです。

インスタンスが別のタイプのサブタイプであるタイプである場合、そのインスタンスはそのスーパータイプ(より一般的なタイプ)のインスタンスでもあります。

汎化

GEN論理図

Givenが𝑒を表明し、𝑒が𝜎であり、 𝛼がvariablesの自由変数の要素ではないことを
前提に、𝚪が𝚪を表明し、すべての引数式の型𝛼 𝛼 𝛼式を返す

つまり、generalは𝑒であり、𝛼は自由変数ではないことがわかっているため、一般に、returningはすべての引数変数(𝛼)に対してtypeと入力され、𝜎を返します。

これは、包含スコープでまだバインドされていない引数(ローカルでない変数)のすべての型を受け入れるようにプログラムを一般化できることを意味します。これらのバインドされた変数は置換可能です。

すべてを一緒に入れて

特定の仮定(自由/未定義の変数がない、既知の環​​境など)を前提として、次のタイプを知っています。

  • プログラムのアトミック要素(変数)、
  • 関数(関数アプリケーション)から返される値
  • 関数構造(関数抽象化)、
  • letバインディング(変数宣言を許可)、
  • インスタンスの親タイプ(インスタンス化)、および
  • すべての式(汎化)。

結論

これらのルールを組み合わせることで、型注釈を必要とせずに、アサートされたプログラムの最も一般的なタイプを証明できます。


1
このような良い要約アーロン!
bhurlow

48

表記は自然控除から来ています。

⊢記号は回転木戸と呼ばれます。

6つのルールはとても簡単です。

Var ルールはかなり自明なルールです。識別子のタイプがタイプ環境にすでに存在する場合、タイプを推測するには、環境からそのままそれを取得するだけです。

Appルールによると、2つの識別子がe0ありe1、それらのタイプを推測できる場合、アプリケーションのタイプを推測できますe0 e1。あなたはそれを知っていれば、ルールは次のように読み込むe0 :: t0 -> t1e1 :: t0(同じt0は!)、そしてアプリケーションがうまく型付けで、タイプがありますt1

Absそして、Letラムダ抽象化のための型を推測してみましょう-にするためのルールです。

Inst ルールによると、型を一般的でない型に置き換えることができます。


4
これは後続の計算であり、自然な控除ではありません。
Roman Cheplyaka 2012

12
@RomanCheplyakaまあ、表記はほとんど同じです。ウィキペディアの記事には、2つの手法の興味深い比較があります:en.wikipedia.org/wiki/Natural_deduction#Sequent_calculus。次の微積分は自然な演繹の失敗に直接対応して生まれたので、質問が「この表記はどこから来たのか」である場合、技術的には「自然な演繹」がより正しい答えです。
Dan Burton

2
@RomanCheplyakaもう1つの考慮事項は、後続の微積分は純粋に構文である(そのため、構造規則が非常に多い)ことですが、この表記はそうではありません。最初のルールは、コンテキストがセットであると仮定していますが、後続の計算では、より単純な構文構成です。
nponeccop 2012

@Cheplyaka実際には、「シーケント」のように見えますが、シーケンシャル計算ではありません。ヘイパーは彼の教科書でこれを「高次の判決」として理解を深めている。これは本当に自然な控除です。
フィリップJF

15

eについて考える方法は2つあります:σ。1つは「式eの型がσである」、もう1つは「式eと型σの順序付けられたペア」です。

Γを、式とタイプのペアのセットe:σとして実装された式のタイプに関する知識と見なします。

回転木戸⊢は、左側の知識から、右側にあるものを推測できることを意味します。

したがって、最初のルール[Var]を読み取ることができます。
知識Γにe:σのペアが含まれている場合、Γからeのタイプがσであると推定できます。

2番目のルール[App]を読むことができます:
fromからe_0の型がτ→τ 'であると推定でき、Ifからe_1の型がτであると推定できる場合、Γからe_0 e_1にτ 'と入力します。

Γ∪{e:σ}の代わりにΓ、e:σと書くのが一般的です。

したがって、3番目のルール[Abs]は次のように読み取ることができます
。xで拡張されたfromから、τがeのタイプがτ 'であると推定できる場合、Γからλx.eのタイプがτ→τ'であると推定できます。

4番目のルール[Let]は演習として残します。:-)

5番目のルール[Inst]を読むことが
できます。Ifからの式がeの型がσ 'であると推定できる場合、σ'がσのサブタイプである場合、Γからの式でeの型がσであると推定できます。

6番目と最後の規則[Gen]を読み取ることが
できます。Γからの式がeの型σであると推定でき、αがΓのいずれの型でもフリー型変数でない場合、Γの式からeが型を持つと推定できます。 ∀ασ。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.