ラムダ計算で型のリハビリ

2024/02/20

TAPLの表紙

TAPLを読んでから約2年が経過しました。

忘れた頃にやる勉強が一番良いらしいので、型のリハビリをしていこうと思います。単純な自作の言語を定義し、その上に型システムを導入し、もろもろの性質を証明していきます。

これ以降は、説明なしに型理論の記法がいろいろ登場します。ごめんなさい。必要に応じてTAPLを参照していただければと思います。

抽象構文

今回作成する言語は以下のような感じです。

t ::=             項:
  x                 変数
  λx:T. t           ラムダ抽象
  t t               適用
  0                 ゼロ
  succ t            後者値
  let x = t in t    let束縛

v ::=             値:
  λx:T. t           ラムダ抽象
  nv                数値

nv ::=            数値:
  0                 ゼロ
  succ nv           後者値

T ::=             型:
  T→T               関数型
  Nat               自然数型

Γ ::=             文脈:
  ∅                 空の文脈
  Γ,x:T             束縛

典型的なラムダ計算 + αです。ラムダ計算は、関数だけでいろいろ計算できちゃうというのがかっこいいです。かっこいいですよね?(確認)

数値は、最終的な計算結果を表すために導入しました。計算結果を表示するPrinterには、succ (succ (... (succ 0) ...))を数字に変換する機能をつけようと思います。

let束縛は便利なので入れました。

評価

評価規則を定義することで、言語に意味を与えます。

t1t1t1 t2t1 t2(E-App1)\dfrac { t_1 \longrightarrow t'_1 } { t_1 ~ t_2 \longrightarrow t'_1 ~ t_2 } \quad\text{(E-App1)}
t2t2v1 t2v1 t2(E-App2)\dfrac { t_2 \longrightarrow t'_2 } { v_1 ~ t_2 \longrightarrow v_1 ~ t'_2 } \quad\text{(E-App2)}
(λx:T11. t12) v2[xv2]t12(E-AppAbs)(\lambda x : T_{11} . ~ t_{12}) ~ v_2 \longrightarrow [x \mapsto v_2]t_{12} \quad\text{(E-AppAbs)}
t1t1succ t1succ t1(E-Succ)\dfrac { t_1 \longrightarrow t'_1 } { \text{succ} ~ t_1 \longrightarrow \text{succ} ~ t'_1 } \quad\text{(E-Succ)}
t1t1let x = t1 in t2let x = t1 in t2(E-Let)\dfrac { t_1 \longrightarrow t'_1 } { \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 \longrightarrow \text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t_2 } \quad\text{(E-Let)}
let x = v1 in t2[xv1]t2(E-LetV)\text{let} ~ x ~ \text{=} ~ v_1 ~ \text{in} ~ t_2 \longrightarrow [x \mapsto v_1]t_{2} \quad\text{(E-LetV)}
定義:代入
[xs]x=s[xs]y=y(if yx)[xs](λy. t)=λy. [xs]t(if yx and yFV(s))[xs](t1 t2)=[xs]t1 [xs]t2[xs]0=0[xs](succ t)=succ [xs](t)[xs](let y = t1 in t2)=(let y = [xs]t1 in [xs]t2)(if yx and yFV(s))\begin{aligned} [x \mapsto s]x &= s \\ [x \mapsto s]y &= y \quad (\text{if} ~ y \ne x) \\ [x \mapsto s](\lambda y . ~ t) &= \lambda y . ~ [x \mapsto s] t \quad (\text{if} ~ y \ne x ~ \text{and} ~ y \notin FV(s)) \\ [x \mapsto s](t_1 ~ t_2) &= [x \mapsto s]t_1 ~ [x \mapsto s]t_2 \\ [x \mapsto s]0 &= 0 \\ [x \mapsto s](\text{succ} ~ t) &= \text{succ} ~ [x \mapsto s](t) \\ [x \mapsto s](\text{let} ~ y ~ = ~ t_1 ~ \text{in} ~ t_2) &= (\text{let} ~ y ~ = ~ [x \mapsto s]t_1 ~ \text{in} ~ [x \mapsto s]t_2) \quad (\text{if} ~ y \ne x ~ \text{and} ~ y \notin FV(s)) \\ \end{aligned}

まぁそうなるよね、という感じです。

型付け

型を付けていきます。

x:TΓΓx:T(T-Var)\dfrac { x : T \in \Gamma } { \Gamma \vdash x : T } \quad\text{(T-Var)}
Γ,x:T1t2:T2Γλx:T1. t2:T1T2(T-Abs)\dfrac { \Gamma , x : T_1 \vdash t_2 : T_2 } { \Gamma \vdash \lambda x: T_1 . ~ t_2 : T_1 \rightarrow T_2 } \quad\text{(T-Abs)}
Γt1:T11T12Γt2:T11Γt1 t2:T12(T-App)\dfrac { \Gamma \vdash t_1 : T_{11} \rightarrow T_{12} \qquad \Gamma \vdash t_2 : T_{11} } { \Gamma \vdash t_1 ~ t_2 : T_{12} } \quad\text{(T-App)}
Γ0:Nat(T-Zero)\Gamma \vdash 0 : \text{Nat} \quad\text{(T-Zero)}
Γt1:NatΓsucc t1:Nat(T-Succ)\dfrac { \Gamma \vdash t_1 : \text{Nat} } { \Gamma \vdash \text{succ} ~ t_1 : \text{Nat} } \quad\text{(T-Succ)}
Γt1:T1Γ,x:T1t2:T2Γlet x = t1 in t2:T2(T-Let)\dfrac { \Gamma \vdash t_1 : T_1 \qquad \Gamma , x : T_1 \vdash t_2 : T_2 } { \Gamma \vdash \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2 } \quad\text{(T-Let)}
文脈に関する暗黙の仮定
  1. 文脈に束縛を追加するとき、すでに束縛している名前とは別のものを追加する。
  2. 文脈のすべての束縛は別々の変数名を持つ。
  • 1について、文脈に束縛を追加するのはT-Absだけである。ラムダ抽象の変数を束縛するときに、必要に応じてフレッシュな変数を用いてα-変換することで、名前の衝突を避けられる。
  • 2について、1の性質より成り立つ

ふむり。

進行

おまたせしました、リハビリタイムです。さきほど定義した言語が、安全であることを証明します。

証明の大きな流れはTAPLを参考にしていますが、各議論や式変形は、僕でもわかるようにできるだけ細かく書くようにします。なのでめっちゃ長いです。読み飛ばしましょう。

安全性は、進行と保存によって示します。

まず、以下のように進行定理を示します。そのために、逆転補題と標準形補題という基本的な性質を示します。

補題:逆転
  1. Γx:R\Gamma \vdash x : R ならば、 x:RΓx : R \in \Gamma である。
  2. Γλx:T1. t2:R\Gamma \vdash \lambda x : T_1 . ~ t_2 : R ならば、Γ,x:T1t2:R2\Gamma , x : T_1 \vdash t_2 : R_2 を満たす R2R_2 が存在し、 R=T1R2R = T_1 \rightarrow R_2 である。
  3. Γt1 t2:R\Gamma \vdash t_1 ~ t_2 : R ならば、 Γt1:T11R\Gamma \vdash t_1 : T_{11} \rightarrow RΓt2:T11\Gamma \vdash t_2 : T_{11} を満たす T11T_{11} が存在する。
  4. Γ0:R\Gamma \vdash 0 : R ならば、 R=NatR = \text{Nat} である。
  5. Γsucc t1:R\Gamma \vdash \text{succ} ~ t_1 : R ならば、 R=NatR = \text{Nat} かつ Γt1:Nat\Gamma \vdash t_1 : \text{Nat} である。
  6. Γlet x = t1 in t2:R\Gamma \vdash \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : R ならば、 Γt1:T1\Gamma \vdash t_1 : T_1Γ,x:T1t2:R\Gamma , x : T_1 \vdash t_2 : R を満たす T1T_1 が存在する。

概要:ある項にある型が付いているとき、項の形から型の形をいえる補題。

証明:

型付け規則の定義より自明。

補題:標準形
  1. vvT1T2T_1 \rightarrow T_2 型の値ならば、 v=λx:T1. t2v = \lambda x : T_1 . ~ t_2 である。
  2. vvNat\text{Nat} 型の値ならば、 vv は抽象構文にしたがった数値である。

概要:ある値にある型が付いているとき、型の形から値の形をいえる補題。

証明:

抽象構文の定義によれば、値である vv

  • λx:T1.tλx:T_1. t
  • 00
  • succ nv\text{succ} ~ \text{nv}

のいずれかの形。

補題のそれぞれの節について、 vv をこれら3つのパターンに分けて検証すれば十分である。

  • 1について、
    • vvλx:T1.tλx:T_1. t 型の場合、逆転補題2より T1R2T_1 \rightarrow R_2 型が付く。そのため前提を満たし、結論も満たす。
    • vv00 の場合、逆転補題4より関数型が付かないため前提を満たさない。
    • vvsucc nv\text{succ} ~ \text{nv} の場合、逆転補題5より関数型が付かないため前提を満たさない。
  • 2について、
    • vvλx:T1.tλx:T_1. t 型の場合、逆転補題2より Nat\text{Nat} 型が付かないため前提を満たさない。
    • vv00 の場合、逆転補題4より Nat\text{Nat} 型が付くため前提を満たす。抽象構文の定義によれば0は数値であるため、結論も満たす。
    • vvsucc nv\text{succ} ~ \text{nv} の場合、逆転補題5より Nat\text{Nat} 型が付くため前提を満たす。抽象構文の定義によれば succ nv\text{succ} ~ \text{nv} は数値であるため、結論も満たす。

で、これらを使って進行を示します。

定理:進行

t:T\vdash t : T ならば tt は値であるか、ある tt' が存在して ttt \longrightarrow t' である。

概要:空の文脈で型が付いた項は値であるか、別の形に評価できる。

証明:

t:T\vdash t : T の導出に関する構造的帰納法によって示す。

構造的帰納法のしくみ

ここでは、すべての型付け規則について、(必要であれば)前提(線の上)が所望の性質を満たすと仮定して、結論(線の下)もまた性質を満たすことを示します。

これでなぜ証明になるのかというと、例えば t:T\vdash t : T に対応する導出木が以下のような形であるとします。

A(T-Y)B(T-Z)t:T(T-X)\dfrac { \dfrac {\vdots} {A} \quad\text{\small(T-Y)} \qquad \dfrac {\vdots} {B} \quad\text{\small(T-Z)} } { \vdash t : T } \quad\text{\small(T-X)}

ここで、導出木の一番下で使われた規則T-Xに着目します。T-Xがどの型付け規則であっても、その前提であるAとBが所望の性質を満たすと仮定すると、 t:T\vdash t : T でも性質を満たしていると言えて、証明が完了します。さきほど、これをすべての型付け規則について示したからです。

ではAやBが性質を満たすのはどう示すのかというと、同じようにT-YやT-Zについて、それらの前提で性質を仮定すれば示せます。このように、木の葉に向かって性質を示していけます。数学的帰納法の感覚に似ていますね。

というわけで、性質を「 t:T\vdash t : T ならば tt は値であるか、ある tt' が存在して ttt \longrightarrow t' である 」として、それぞれの型付け規則について、前提での性質を仮定し、結論もまた性質を満たすことを示します。

  • T-Varの場合、
    • 定理とT-Varの結論を以下のように対応付ける(左辺が定理、右辺がT-Varの結論。名前が違う意味で衝突するときは、右辺の名前を優先して変える)
      • =Γ\varnothing = \Gamma
    • 空の文脈でT-Verに型は付けられないため、定理の前提は成立せず、所望の結論は自明に満たされる。
      • メモ:T-Varの前提は空の文脈では成立しない。導出木の一番下は t:T\vdash t : T であり、文脈は空である。型付け規則を下から上に読むと、T-Absのみが文脈に束縛を追加する。そのため、導出木でT-Varが使われているとしたら、それはT-Absより上にある。しかしT-Absでは、前提で性質を仮定せず、結論のみで性質を満たせる。したがって、T-Varの場合を示す必要はない。
  • T-Absの場合、
    • 定理とT-Absの結論を以下のように対応付ける。
      • t=λx:T1. t2t = \lambda x: T_1 . ~ t_2
    • tt は値であるため性質を満たす。
  • T-Appの場合、
    • 定理とT-Appの結論を以下のように対応付ける。
      • =Γ\varnothing = \Gamma
      • t=t1 t2t = t_1 ~ t_2
    • T-Appの前提より、
      • t1:T11T12\vdash t_1 : T_{11} \rightarrow T_{12}
    • 帰納法の仮定より、
      • t1t_1 は値であるか、ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1
      • t2t_2 は値であるか、ある t2t'_2 が存在して t2t2t_2 \longrightarrow t'_2
    • t1t_1 が値の場合、
      • t2t_2 が値の場合、
        • t1t_1T11T12T_{11} \rightarrow T_{12} 型の値であるため、標準形補題より t1=λx:T11. t12t_1 = \lambda x : T_{11} . ~ t_{12} である。
        • E-AppAbsにより t=(λx:T11. t12) t2[xt2]t12=tt = (\lambda x : T_{11} . ~ t_{12}) ~ t_2 \longrightarrow [x \mapsto t_2]t_{12} = t' と評価できる。
      • ある t2t'_2 が存在して t2t2t_2 \longrightarrow t'_2 である場合、E-App2により t=t1 t2t1 t2=tt = t_1 ~ t_2 \longrightarrow t_1 ~ t'_2 = t' と評価できる。
    • ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1 である場合、E-App1により t=t1 t2t1 t2=tt = t_1 ~ t_2 \longrightarrow t'_1 ~ t_2 = t' と評価できる。
  • T-Zeroの場合、
    • 定理とT-Zeroの結論を以下のように対応付ける。
      • t=0t = 0
    • tt は値であるため性質を満たす。
  • T-Succの場合、
    • 定理とT-Succの結論を以下のように対応付ける。
      • t=succ t1t = \text{succ} ~ t_1
    • T-Succの前提より、
      • t1:Nat\vdash t_1 : \text{Nat}
    • 帰納法の仮定より、
      • t1t_1 は値であるか、ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1
    • t1t_1 が値の場合、 t1t_1Nat\text{Nat} 型の値であるから、標準形補題より t1t_1 は抽象構文にしたがった数値である。抽象構文の定義より t=succ t1t = \text{succ} ~ t_1 もまた数値であり、数値は値であるから性質を満たす。
    • ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1 である場合、E-Succにより t=succ t1succ t1=tt = \text{succ} ~ t_1 \longrightarrow \text{succ} ~ t'_1 = t' と評価できる。
  • T-Letの場合、
    • 定理とT-Letの結論を以下のように対応付ける。
      • t=(let x = t1 in t2)t = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2)
    • 帰納法の仮定より、
      • t1t_1 は値であるか、ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1
    • t1t_1 が値の場合、E-LetVにより t=(let x = t1 in t2)[xt1]t2=tt = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) \longrightarrow [x \mapsto t_1]t_{2} = t' と評価できる。
    • ある t1t'_1 が存在して t1t1t_1 \longrightarrow t'_1 である場合、E-Letにより t=(let x = t1 in t2)(let x = t1 in t2)=tt = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) \longrightarrow (\text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t_2) = t' と評価できる。

よーし。

保存

次に保存定理を示します。これは進行よりも難しいです。

特に代入補題と呼ばれるやつはTAPLで最も重要と言って良いとのことで、この補題を示すためにさらに補題が2つ必要です。

がんばるぞ。

補題:並べ替え

Γt:T\Gamma \vdash t : T かつ、 Δ\DeltaΓ\Gamma の並べ替えならば、 Δt:T\Delta \vdash t : T である。さらに、前者と後者の導出の深さ(導出木の高さ)は同じ。

概要:文脈の要素を並べ替えても、その文脈のもとで型付けができる。

証明:

Γt:T\Gamma \vdash t : T の導出に関するごく簡単な構造的帰納法によって示す。

  • T-Varの場合、
    • 文脈に関する暗黙の仮定より、変数名がそれぞれ異なる文脈を並べ替えたとしても x:TΔx : T \in \Delta が成り立つため、 T-Varより Δx:T\Delta \vdash x : T もまた成り立つ。
    • 並び替え前後で導出の深さは変化していない。
  • T-Absの場合、
    • 帰納法の仮定より、 Δ,x:T1t2:T2\Delta , x : T_1 \vdash t_2 : T_2 であるため、T-Absより Δλx:T1. t2:T1T2\Delta \vdash \lambda x: T_1 . ~ t_2 : T_1 \rightarrow T_2 が成り立ち、これは所望の結論である。
      • 以降、同様の形式の議論について「帰納法の仮定とT-Xから、所望の結論が成り立つ」と表現する。
    • 並び替え前後で導出の深さは変化していない。
  • T-Appの場合、
    • 帰納法の仮定とT-Appから、所望の結論が成り立つ
    • 並び替え前後で導出の深さは変化していない。
  • T-Zeroの場合、
    • 前提がないため、T-Zeroにより即座に Δ0:Nat\Delta \vdash 0 : \text{Nat} が成り立つ。
    • 並び替え前後で導出の深さは変化していない。
  • T-Succの場合、
    • 帰納法の仮定とT-Succから、所望の結論が成り立つ
    • 並び替え前後で導出の深さは変化していない。
  • T-Letの場合、
    • 帰納法の仮定とT-Letから、所望の結論が成り立つ
    • 並び替え前後で導出の深さは変化していない。
補題:弱化

Γt:T\Gamma \vdash t : T かつ、 xdom(Γ)x \notin dom(\Gamma) ならば、 Γ,x:St:T\Gamma , x : S \vdash t : T である。さらに、前者と後者で導出の深さ(導出木の高さ)は同じ。

概要:文脈に現れない変数の束縛を追加しても、その文脈のもとで型付けができる。

証明:

Γt:T\Gamma \vdash t : T の導出に関するごく簡単な構造的帰納法によって示す。

  • T-Varの場合、
    • xdom(Γ)x' \notin dom(\Gamma) である x:Sx' : SΓ\Gamma に追加したとしても、 x:TΓ,x:Sx : T \in \Gamma , x' : S であることは変わらないため、 T-Varより Γ,x:Sx:T\Gamma , x' : S \vdash x : T が成り立つ。
    • 束縛の追加前後で導出の深さは変化していない。
  • T-Absの場合、
    • 帰納法の仮定より、xdom(Γ)x' \notin dom(\Gamma) である x:Sx' : S について、 Γ,x:T1,x:St2:T2\Gamma , x : T_1 , x' : S \vdash t_2 : T_2 である。T-Absより、 Γ,x:Sλx:T1. t2:T1T2\Gamma , x' : S \vdash \lambda x: T_1 . ~ t_2 : T_1 \rightarrow T_2 が成り立ち、これは所望の結論である。
      • 以降、同様の議論について「帰納法の仮定とT-Xから、所望の結論が成り立つ」と表現する。
    • 束縛の追加前後で導出の深さは変化していない。
  • T-Appの場合、
    • 帰納法の仮定とT-Appから、所望の結論が成り立つ。
    • 束縛の追加前後で導出の深さは変化していない。
  • T-Zeroの場合、
    • 前提がないため、 xdom(Γ)x' \notin dom(\Gamma) である x:Sx' : S について、T-Zeroにより即座に Γ,x:S0:Nat\Gamma , x' : S \vdash 0 : \text{Nat} が成り立つ。
    • 束縛の追加前後で導出の深さは変化していない。
  • T-Succの場合、
    • 帰納法の仮定とT-Succから、所望の結論が成り立つ。
    • 束縛の追加前後で導出の深さは変化していない。
  • T-Letの場合、
    • 帰納法の仮定とT-Letから、所望の結論が成り立つ。
    • 束縛の追加前後で導出の深さは変化していない。

これらを使って代入を示します。

補題:代入

Γ,x:St:T\Gamma , x : S \vdash t : T かつ、 Γs:S\Gamma \vdash s : S ならば、 Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T である。

概要:型付けされた項 tt について、文脈中の任意の束縛 x:Sx : S を取り出して、その束縛なしに SS 型が付く項 ss があるなら、[xs]t[x \mapsto s]t にも型が付く。

証明:

Γ,x:St:T\Gamma , x : S \vdash t : T の導出に関する構造的帰納法によって示す。

  • T-Varの場合、
    • 補題とT-Varの結論を以下のように対応付ける。
      • t=yt = y
    • 補題の1つ目の前提より
      • Γ,x:St:T\Gamma , x : S \vdash t : T
      • Γ,x:Sy:T\Gamma , x : S \vdash y : T
      • 逆転補題1によって、
      • y:TΓ,x:Sy : T \in \Gamma , x : S
    • 補題のもう1つの前提より
      • Γs:S\Gamma \vdash s : S
    • 所望の結論は、 Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T である。代入の定義より、 x=yx = yxyx \ne y の場合を検証すれば十分である。
      • x=yx = y の場合、
        • y:TΓ,x:Sy : T \in \Gamma , x : S から T=ST = S である。
        • 所望の結論は
          • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
          • Γ[xs]y:T\Gamma \vdash [x \mapsto s]y : T
          • Γs:T\Gamma \vdash s : T
          • Γs:S\Gamma \vdash s : S
        • であり、これは補題の前提に含まれるため所望の性質を満たす。
      • xyx \ne y の場合、
        • y:TΓ,x:Sy : T \in \Gamma , x : S について、 x:Sx : Syy と無関係の束縛のため、 y:TΓy : T \in \Gamma である。
        • 所望の結論は
          • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
          • Γ[xs]y:T\Gamma \vdash [x \mapsto s]y : T
          • Γy:T\Gamma \vdash y : T
        • であり、これは y:TΓy : T \in \Gamma と T-Varより成り立つ。
  • T-Absの場合、
    • 補題とT-Absの結論を以下のように対応付ける。
      • Γ,x:S=Δ\Gamma , x : S = \Delta
      • t=λy:T1. t2t = \lambda y: T_1 . ~ t_2
        • ただし、 yxy \ne x かつ yFV(s)y \notin FV(s) かつ ydom(Γ)y \notin dom(\Gamma) を仮定する (仮定1)
        • フレッシュな変数を選び、もとのラムダ抽象をα-変換することでこの仮定はいつでも満たせる。
      • T=T1T2T = T_1 \rightarrow T_2
    • T-Absの前提は
      • Δ,y:T1ts:T2\Delta , y : T_1 \vdash t_s : T_2
      • Γ,x:S,y:T1t2:T2\Gamma , x : S , y : T_1 \vdash t_2 : T_2
      • 並び替え補題より
      • Γ,y:T1,x:St2:T2\Gamma , y : T_1 , x : S \vdash t_2 : T_2 (1)
    • 補題の前提より、
      • Γs:S\Gamma \vdash s : S
      • 弱化補題と仮定1より
      • Γ,y:T1s:S\Gamma , y : T_1 \vdash s : S (2)
    • 帰納法の仮定より、1と2に補題を適用して
      • Γ,y:T1[xs]t2:T2\Gamma , y : T_1 \vdash [x \mapsto s]t_2 : T_2
      • T-Absより
      • Γλy:T1. [xs]t2:T1T2\Gamma \vdash \lambda y : T_1 . ~ [x \mapsto s]t_2 : T_1 \rightarrow T_2
      • Γλy:T1. [xs]t2:T\Gamma \vdash \lambda y : T_1 . ~ [x \mapsto s]t_2 : T (3)
    • 所望の結論は
      • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
      • Γ[xs](λy:T1. t2):T\Gamma \vdash [x \mapsto s](\lambda y: T_1 . ~ t_2) : T
      • 代入の定義と仮定1より
      • Γλy:T1. [xs]t2:T\Gamma \vdash \lambda y : T_1 . ~ [x \mapsto s]t_2 : T (3)
    • 3は型付けの前提、補題の前提および帰納法の仮定のみから得られるため、所望の結論は満たされる。
  • T-Appの場合、
    • 補題とT-Appの結論を以下のように対応付ける。
      • Γ,x:S=Δ\Gamma , x : S = \Delta
      • t=t1 t2t = t_1 ~ t_2
      • T=T12T = T_{12}
    • T-Appの前提は
      • Γ,x:St1:T11T12\Gamma , x : S \vdash t_1 : T_{11} \rightarrow T_{12} (1)
      • Γ,x:St2:T11\Gamma , x : S \vdash t_2 : T_{11} (2)
    • 補題の前提より
      • Γs:S\Gamma \vdash s : S (3)
    • 帰納法の仮定より、補題を1と3に適用して
      • Γ[xs]t1:T11T12\Gamma \vdash [x \mapsto s]t_1 : T_{11} \rightarrow T_{12} (4)
    • 帰納法の仮定より、補題を2と3に適用して
      • Γ[xs]t2:T11\Gamma \vdash [x \mapsto s]t_2 : T_{11} (5)
    • 4、5とT-Appより
      • Γ[xs]t1 [xs]t2:T12\Gamma \vdash [x \mapsto s]t_1 ~ [x \mapsto s]t_2 : T_{12}
      • Γ[xs]t1 [xs]t2:T\Gamma \vdash [x \mapsto s]t_1 ~ [x \mapsto s]t_2 : T
      • Γ[xs](t1 t2):T\Gamma \vdash [x \mapsto s](t_1 ~ t_2) : T
      • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
    • となるため、所望の結論が成り立つ。
  • T-Zeroの場合、
    • 補題とT-Zeroの結論を以下のように対応付ける。
      • Γ,x:S=Δ\Gamma , x : S = \Delta
      • t=0t = 0
      • T=NatT = \text{Nat}
    • 所望の結論は
      • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
      • Γ[xs]0:Nat\Gamma \vdash [x \mapsto s]0 : \text{Nat}
      • Γ0:Nat\Gamma \vdash 0 : \text{Nat}
    • となり、T-Zeroより即座に成り立つ。
  • T-Succの場合、
    • 補題とT-Succの結論を以下のように対応付ける。
      • Γ,x:S=Δ\Gamma , x : S = \Delta
      • t=succ t1t = \text{succ} ~ t_1
      • T=NatT = \text{Nat}
    • T-Succの前提は
      • Δt1:Nat\Delta \vdash t_1 : \text{Nat}
      • Γ,x:St1:Nat\Gamma , x : S \vdash t_1 : \text{Nat} (1)
    • 補題の前提より
      • Γs:S\Gamma \vdash s : S (2)
    • 帰納法の仮定より、1と2に補題を適用して
      • Γ[xS]t1:Nat\Gamma \vdash [x \mapsto S]t_1 : \text{Nat}
      • T-Succより
      • Γsucc [xS]t1:Nat\Gamma \vdash \text{succ} ~ [x \mapsto S]t_1 : \text{Nat}
      • Γ[xS](succ t1):Nat\Gamma \vdash [x \mapsto S](\text{succ} ~ t_1) : \text{Nat}
      • Γ[xS]t:Nat\Gamma \vdash [x \mapsto S]t : \text{Nat}
      • Γ[xS]t:T\Gamma \vdash [x \mapsto S]t : T
    • となるため、所望の結論が成り立つ。
  • T-Letの場合、
    • 補題とT-Letの結論を以下のように対応付ける。
      • Γ,x:S=Δ\Gamma , x : S = \Delta
      • t=(let y = t1 in t2:T2)t = (\text{let} ~ y ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2)
        • ただし、 yxy \ne x かつ yFV(s)y \notin FV(s) かつ ydom(Γ)y \notin dom(\Gamma) を仮定する (仮定1)
        • フレッシュな変数を選び、 t2t_2 内のもとの変数を置き換えることでこの仮定はいつでも満たせる。
      • T=T2T = T_2
    • T-Letの前提は
      • Γ,x:St1:T1\Gamma , x : S \vdash t_1 : T_1 (1)
      • Γ,x:S,y:T1t2:T2\Gamma , x : S , y : T_1 \vdash t_2 : T_2 (2)
    • 補題の前提より
      • Γs:S\Gamma \vdash s : S (3)
      • 弱化補題と仮定1より
      • Γ,y:T1s:S\Gamma , y : T_1 \vdash s : S (4)
    • 帰納法の仮定より、1と3に補題を適用して
      • Γ[xs]t1:T1\Gamma \vdash [x \mapsto s]t_1 : T_1 (5)
    • 2に並べ替え補題を適用して
      • Γ,y:T1,x:St2:T2\Gamma , y : T_1 , x : S \vdash t_2 : T_2
      • 帰納法の仮定より、4と補題を適用して
      • Γ,y:T1[xs]t2:T2\Gamma , y : T_1 \vdash [x \mapsto s]t_2 : T_2 (6)
    • 5、6、T-Letより
      • Γlet y = [xs]t1 in [xs]t2:T2\Gamma \vdash \text{let} ~ y ~ \text{=} ~ [x \mapsto s]t_1 ~ \text{in} ~ [x \mapsto s]t_2 : T_2
      • Γlet y = [xs]t1 in [xs]t2:T\Gamma \vdash \text{let} ~ y ~ \text{=} ~ [x \mapsto s]t_1 ~ \text{in} ~ [x \mapsto s]t_2 : T (7)
    • 所望の結論は
      • Γ[xs]t:T\Gamma \vdash [x \mapsto s]t : T
      • Γ[xs](let y = t1 in t2:T2):T\Gamma \vdash [x \mapsto s](\text{let} ~ y ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2) : T
      • 代入の定義と仮定1より
      • Γlet y = [xs]t1 in [xs]t2:T2:T\Gamma \vdash \text{let} ~ y ~ \text{=} ~ [x \mapsto s]t_1 ~ \text{in} ~ [x \mapsto s]t_2 : T_2 : T (7)
    • 7は型付けの前提、補題の前提および帰納法の仮定のみから得られるため、所望の結論は満たされる。

で、代入を使って保存を示します。

定理:保存

Γt:T\Gamma \vdash t : T かつ ttt \longrightarrow t' ならば Γt:T\Gamma \vdash t' : T

概要:項を評価しても同じ型が付く。

証明:

Γt:T\Gamma \vdash t : T の導出に関する構造的帰納法によって示す。

  • T-Varの場合、
    • 定理とT-Varの結論を以下のように対応付ける。
      • t=xt = x
    • tt は変数であり、変数は評価できないため定理の前提を満たさない。したがって所望の結論は自明に満たされる。
  • T-Absの場合、
    • 定理とT-Absの結論を以下のように対応付ける。
      • t=λx:T1. t2t = \lambda x: T_1 . ~ t_2
    • tt はラムダ抽象であり、ラムダ抽象は評価できないため定理の前提を満たさない。したがって所望の結論は自明に満たされる。
  • T-Appの場合、
    • 定理とT-Appの結論を以下のように対応付ける。
      • t=t1 t2t = t_1 ~ t_2
      • T=T12T = T_{12}
    • T-Appの前提より
      • Γt1:T11T12\Gamma \vdash t_1 : T_{11} \rightarrow T_{12} (1)
      • Γt2:T11\Gamma \vdash t_2 : T_{11} (2)
    • 帰納法の仮定と1、2より
      • t1t1t_1 \longrightarrow t'_1
      • Γt1:T11T12\Gamma \vdash t'_1 : T_{11} \rightarrow T_{12} (3)
      • t2t2t_2 \longrightarrow t'_2
      • Γt2:T11\Gamma \vdash t'_2 : T_{11} (4)
    • 定理の前提より
      • ttt \longrightarrow t' (5)
    • tt に適用されうる評価規則はE-App1、E-App2、E-AppAbsであるため、それぞれのケースを検証すれば十分である。
      • E-App1の場合、
        • 5とE-App1の結論を対応付けると
          • t=t1 t2t' = t'_1 ~ t_2
        • 3と2、T-Appより
          • Γt1 t2:T12\Gamma \vdash t'_1 ~ t_2 : T_{12}
          • Γt1 t2:T\Gamma \vdash t'_1 ~ t_2 : T
          • Γt:T\Gamma \vdash t' : T
        • となるため、所望の結論を満たす。
      • E-App2の場合、
        • 5とE-App2の結論を対応付けると
          • t=t1 t2t' = t_1 ~ t'_2
        • 1と4、T-Appより
          • Γt1 t2:T12\Gamma \vdash t_1 ~ t'_2 : T_{12}
          • Γt1 t2:T\Gamma \vdash t_1 ~ t'_2 : T
          • Γt:T\Gamma \vdash t' : T
        • となるため、所望の結論を満たす。
      • E-AppAbsの場合、
        • 5とE-AppApsの結論を対応付けると
          • t1=λx:T11. t12t_1 = \lambda x : T_{11} . ~ t_{12} (6)
          • t=[xt2]t12t' = [x \mapsto t_2]t_{12}
        • 1より
          • Γt1:T11T12\Gamma \vdash t_1 : T_{11} \rightarrow T_{12}
          • 6より
          • Γλx:T11. t12:T11T12\Gamma \vdash \lambda x : T_{11} . ~ t_{12} : T_{11} \rightarrow T_{12}
          • 逆転補題2より
          • Γ,x:T11t12:T12\Gamma , x : T_{11} \vdash t_{12} : T_{12}
          • 2と代入補題より
          • Γ[xt2]t12:T12\Gamma \vdash [x \mapsto t_2]t_{12} : T_{12}
          • Γt:T12\Gamma \vdash t' : T_{12}
          • Γt:T\Gamma \vdash t' : T
        • となるため、所望の結論を満たす。
  • T-Zeroの場合、
    • 定理とT-Zeroの結論を以下のように対応付ける。
      • t=0t = 0
    • tt は0であり、0は評価できないため定理の前提を満たさない。したがって所望の結論は自明に満たされる。
  • T-Succの場合、
    • 定理とT-Succの結論を以下のように対応付ける。
      • t=succ t1t = \text{succ} ~ t_1
      • T=NatT = \text{Nat}
    • T-Succの前提より
      • Γt1:Nat\Gamma \vdash t_1 : \text{Nat} (1)
    • 帰納法の仮定と1より
      • t1t1t_1 \longrightarrow t'_1
      • Γt1:Nat\Gamma \vdash t'_1 : \text{Nat} (2)
    • 定理の前提より
      • ttt \longrightarrow t' (3)
    • tt に適用されうる評価規則はE-Succだけであるため、
      • t=succ t1t' = \text{succ} ~ t'_1
    • 2とT-Succより
      • Γsucc t1:Nat\Gamma \vdash \text{succ} ~ t'_1 : \text{Nat}
      • Γt:Nat\Gamma \vdash t' : \text{Nat}
      • Γt:T\Gamma \vdash t' : T
    • となるため、所望の結論を満たす。
  • T-Letの場合、
    • 定理とT-Succの結論を以下のように対応付ける。
      • t=(let x = t1 in t2)t = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2)
      • T=T2T = T_2
    • T−Letの前提より
      • Γt1:T1\Gamma \vdash t_1 : T_1 (1)
      • Γ,x:T1t2:T2\Gamma , x : T_1 \vdash t_2 : T_2 (2)
    • 帰納法の仮定と1、2より
      • t1t1t_1 \longrightarrow t'_1
      • Γt1:T1\Gamma \vdash t'_1 : T_1 (3)
      • t2t2t_2 \longrightarrow t'_2
      • Γ,x:T1t2:T2\Gamma , x : T_1 \vdash t'_2 : T_2 (4)
    • 定理の前提より
      • ttt \longrightarrow t' (5)
    • tt に適用されうる評価規則はE-Let、E-LetVであるため、それぞれのケースを検証すれば十分である。
      • E-Letの場合、
        • 5とE-Letの結論を対応付けると
          • t=(let x = t1 in t2)t' = (\text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t_2)
        • 3と2、T-Letより
          • Γlet x = t1 in t2:T2\Gamma \vdash \text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t_2 : T_2
          • Γt:T2\Gamma \vdash t' : T_2
          • Γt:T\Gamma \vdash t' : T
        • となるため、所望の結論を満たす。
      • E-LetVの場合、
        • 5とE-LetVの結論を対応付けると
          • t=[xt1]t2t' = [x \mapsto t_1]t_2
        • 2より
          • Γ,x:T1t2:T2\Gamma , x : T_1 \vdash t_2 : T_2
          • 1と代入補題より
          • Γ[xt1]t2:T2\Gamma \vdash [x \mapsto t_1]t_2 : T_2
          • Γt:T2\Gamma \vdash t' : T_2
          • Γt:T\Gamma \vdash t' : T
        • となるため、所望の結論を満たす。

うーし。

型安全性

ここまで来れば勝利確定です。進行定理と保存定理により安全性を示します。

定理:安全性

t:T\vdash t : T かつ ttt \longrightarrow^\ast t' \nrightarrow ならば tt' は値である。

概要:空の文脈で型が付いた tt を評価していって停止するなら、それは値である。

証明:

ttt \longrightarrow^\ast t' の評価の長さ nn による数学的帰納法によって示す。

  • n=0n = 0 の場合、
    • 定理の1つ目の前提より
      • t:T\vdash t : T
    • これと進行定理より
      • tt は値であるか、ある tt' が存在して ttt \longrightarrow t'
    • しかし、定理のもう1つの前提より
      • t0tt \longrightarrow^0 t' \nrightarrow
      • つまり
      • tt \nrightarrow
    • したがって tt は値であり、所望の結論を満たす。
  • 任意の nn について定理を仮定し、 n+1n + 1 について示す。
    • 定理の前提より
      • t:T\vdash t : T (1)
      • tn+1tt \longrightarrow^{n + 1} t' \nrightarrow (2)
    • tt の1ステップ評価結果を uu とおくと
      • tut \longrightarrow u (3)
      • untu \longrightarrow^n t' \nrightarrow (4)
    • 保存定理を1と3に適用して
      • u:T\vdash u : T (5)
    • 帰納法の仮定より、定理を5と4に適用すると、 tt' は値であり、所望の結論を満たす。

よっしゃよっしゃよっしゃ

型推論

プログラムにいちいち型を書くのは面倒なので、型推論を実装したいと思います。

型推論は、制約型付けによって制約集合を生成することと、それを単一化アルゴリズムによって解くことで実現できます。

制約型付け

制約型付け規則を定義します。これは先程までの型付け規則に似ていますが、導出の過程で型に関する制約の集合を生成します。

x:TΓΓFx:T F {}(CT-Var)\dfrac { x : T \in \Gamma } { \Gamma \vdash_F x : T ~ |_F ~ \{\} } \quad\text{(CT-Var)}
Γ,x:T1Ft2:T2 F CΓFλx:T1. t2:T1T2 F C(CT-Abs)\dfrac { \Gamma , x : T_1 \vdash_F t_2 : T_2 ~ |_{F'} ~ C } { \Gamma \vdash_F \lambda x : T_1 . ~ t_2 : T_1 \rightarrow T_2 ~ |_{F'} ~ C } \quad\text{(CT-Abs)}
ΓFt1:T1 F C1ΓFt2:T2 F C2F=X,FΓFt1 t2:X F C1C2{T1=T2X}(CT-App)\dfrac { \begin{aligned} & \Gamma \vdash_F t_1 : T_1 ~ |_{F'} ~ C_1 \\ & \Gamma \vdash_{F'} t_2 : T_2 ~ |_{F''} ~ C_2 \\ & F'' = X , F''' \end{aligned} } { \Gamma \vdash_F t_1 ~ t_2 : X ~ |_{F'''} ~ C_1 \cup C_2 \cup \{T_1 = T_2 \rightarrow X \} } \quad\text{(CT-App)}
ΓF0:Nat F {}(CT-Zero)\Gamma \vdash_F 0 : \text{Nat} ~ |_F ~ \{\} \quad\text{(CT-Zero)}
ΓFt1:T F CΓFsucc t1:Nat F C{T=Nat}(CT-Succ)\dfrac { \Gamma \vdash_F t_1 : T ~ |_{F'} ~ C } { \Gamma \vdash_F \text{succ} ~ t_1 : \text{Nat} ~ |_{F'} ~ C \cup \{ T = \text{Nat} \} } \quad\text{(CT-Succ)}
ΓFt1:T1 F C1Γ,x:XFt2:T2 F C2F=X,FΓFlet x = t1 in t2:T2 F C1C2{T1=X}(CT-Let)\dfrac { \begin{aligned} & \Gamma \vdash_F t_1 : T_1 ~ |_{F'} ~ C_1 \\ & \Gamma , x : X \vdash_{F'} t_2 : T_2 ~ |_{F''} ~ C_2 \\ & F'' = X, F''' \end{aligned} } { \Gamma \vdash_F \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2 ~ |_{F'''} ~ C_1 \cup C_2 \cup \{T_1 = X\} } \quad\text{(CT-Let)}

以降は、これらの制約型付けが、通常の型付けと対応することを示していきます。

定義:(Γ,t)(\Gamma, t) の解とは、σΓσt:T\sigma \Gamma \vdash \sigma t : T を満たす (σ,T)(\sigma, T) である。

定義:(Γ,t,S,C)(\Gamma, t, S, C) の解とは、Γt:S  C\Gamma \vdash t : S ~ | ~ C であり、σ\sigmaCC を単一化し、σS=T\sigma S = T となる (σ,T)(\sigma, T) である。

定理:型代入の下での型付けの保存

任意の型代入 σ\sigma について、Γt:T\Gamma \vdash t : T ならば σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T である。

概要:型代入を適用しても型付けは保存される

証明:

Γt:T\Gamma \vdash t : T の導出に関する構造的帰納法による。

  • T-Varの場合、
    • 定理とT-Varの結論を以下のように対応付ける。
      • t=xt = x (1)
    • 定理の前提より
      • Γt:T\Gamma \vdash t : T
      • 1より
      • Γx:T\Gamma \vdash x : T
      • 逆転補題1より
      • x:TΓx : T \in \Gamma
      • 文脈に対する型代入の定義より
      • x:σTσΓx : \sigma T \in \sigma \Gamma
      • T-Varより
      • σΓx:σT\sigma \Gamma \vdash x : \sigma T
      • 変数に対する型代入の定義より
      • σΓσx:σT\sigma \Gamma \vdash \sigma x : \sigma T
      • 1より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
  • T-Absの場合、
    • 定理とT-Absの結論を以下のように対応付ける。
      • t=λx:T1. t2t = \lambda x : T_1 . ~ t_2 (1)
      • T=T1T2T = T_1 \rightarrow T_2 (2)
    • 定理の前提より
      • Γt:T\Gamma \vdash t : T
      • 1と2より
      • Γλx:T1. t2:T1T2\Gamma \vdash \lambda x : T_1 . ~ t_2 : T_1 \rightarrow T_2
      • 逆転補題2より
      • Γ,x:T1t2:T2\Gamma , x : T_1 \vdash t_2 : T_2
      • 帰納法の仮定より
      • σ(Γ,x:T1)σt2:σT2\sigma (\Gamma , x : T_1) \vdash \sigma t_2 : \sigma T_2
      • σΓ,x:σT1σt2:σT2\sigma \Gamma , x : \sigma T_1 \vdash \sigma t_2 : \sigma T_2
      • T-Absより
      • σΓλx:σT1. σt2:σT1σT2\sigma \Gamma \vdash \lambda x : \sigma T_1 . ~ \sigma t_2 : \sigma T_1 \rightarrow \sigma T_2
      • σΓσ(λx:T1. t2):σT1σT2\sigma \Gamma \vdash \sigma (\lambda x : T_1 . ~ t_2) : \sigma T_1 \rightarrow \sigma T_2
      • 2より
      • σΓσt:σT1σT2\sigma \Gamma \vdash \sigma t : \sigma T_1 \rightarrow \sigma T_2
      • σΓσt:σ(T1T2)\sigma \Gamma \vdash \sigma t : \sigma (T_1 \rightarrow T_2)
      • 1より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
  • T-Appの場合、
    • 定理とT-Appの結論を以下のように対応付ける。
      • t=t1 t2t = t_1 ~ t_2 (1)
      • T=T12T = T_{12} (2)
    • 定理の前提より
      • Γt:T\Gamma \vdash t : T
      • 1と2より
      • Γt1 t2:T12\Gamma \vdash t_1 ~ t_2 : T_{12} (3)
    • 3と逆転補題3より
      • Γt1:T11T12\Gamma \vdash t_1 : T_{11} \rightarrow T_{12}
      • 帰納法の仮定より
      • σΓσt1:σ(T11T12)\sigma \Gamma \vdash \sigma t_1 : \sigma (T_{11} \rightarrow T_{12})
      • σΓσt1:σT11σT12\sigma \Gamma \vdash \sigma t_1 : \sigma T_{11} \rightarrow \sigma T_{12} (4)
    • 3と逆転補題3より
      • Γt2:T11\Gamma \vdash t_2 : T_{11}
      • 帰納法の仮定より
      • σΓσt2:σT11\sigma \Gamma \vdash \sigma t_2 : \sigma T_{11} (5)
    • 4、5とT-Appより
      • σΓσt1 σt2:σT12\sigma \Gamma \vdash \sigma t_1 ~ \sigma t_2 : \sigma T_{12}
      • σΓσ(t1 t2):σT12\sigma \Gamma \vdash \sigma (t_1 ~ t_2) : \sigma T_{12}
      • 1より
      • σΓσt:σT12\sigma \Gamma \vdash \sigma t : \sigma T_{12}
      • 2より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
  • T-Zeroの場合、
    • 定理とT-Appの結論を以下のように対応付ける。
      • t=0t = 0 (1)
      • T=NatT = \text{Nat} (2)
    • T-Zeroより
      • σΓ0:Nat\sigma \Gamma \vdash 0 : \text{Nat}
      • 00 に対する型代入の定義より
      • σΓσ0:Nat\sigma \Gamma \vdash \sigma 0 : \text{Nat}
      • Nat\text{Nat} に対する型代入の定義より
      • σΓσ0:σNat\sigma \Gamma \vdash \sigma 0 : \sigma \text{Nat}
      • 1と2より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
  • T-Succの場合、
    • 定理とT-Succの結論を以下のように対応付ける。
      • t=succ t1t = \text{succ} ~ t_1 (1)
      • T=NatT = \text{Nat} (2)
    • 定理の前提より
      • Γt:T\Gamma \vdash t : T
      • 1と2より
      • Γsucc t1:Nat\Gamma \vdash \text{succ} ~ t_1 : \text{Nat}
      • 逆転補題5より
      • Γt1:Nat\Gamma \vdash t_1 : \text{Nat}
      • 帰納法の仮定より
      • σΓσt1:σNat\sigma \Gamma \vdash \sigma t_1 : \sigma \text{Nat}
      • T-Succより
      • σΓsucc (σt1):σNat\sigma \Gamma \vdash \text{succ} ~ (\sigma t_1) : \sigma \text{Nat}
      • σΓσ(succ t1):σNat\sigma \Gamma \vdash \sigma (\text{succ} ~ t_1) : \sigma \text{Nat}
      • 1より
      • σΓσt:σNat\sigma \Gamma \vdash \sigma t : \sigma \text{Nat}
      • 2より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
  • T-Letの場合、
    • 定理とT-Letの結論を以下のように対応付ける。
      • t=(let x = t1 in t2)t = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) (1)
      • T=T2T = T_2 (2)
    • 定理の前提より
      • Γt:T\Gamma \vdash t : T
      • 1と2より
      • Γlet x = t1 in t2:T2\Gamma \vdash \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2 (3)
    • 3と逆転補題6より
      • Γt1:T1\Gamma \vdash t_1 : T_1
      • 帰納法の仮定より
      • σΓσt1:σT1\sigma \Gamma \vdash \sigma t_1 : \sigma T_1 (4)
    • 3と逆転補題6より
      • Γ,x:T1t2:T2\Gamma , x : T_1 \vdash t_2 : T_2
      • 帰納法の仮定より
      • σ(Γ,x:T1)σt2:σT2\sigma (\Gamma , x : T_1) \vdash \sigma t_2 : \sigma T_2
      • σΓ,x:σT1σt2:σT2\sigma \Gamma , x : \sigma T_1 \vdash \sigma t_2 : \sigma T_2 (5)
    • 4、5とT-Letより
      • σΓlet x = σt1 in σt2:σT2\sigma \Gamma \vdash \text{let} ~ x ~ \text{=} ~ \sigma t_1 ~ \text{in} ~ \sigma t_2 : \sigma T_2
      • σΓσ(let x = t1 in t2):σT2\sigma \Gamma \vdash \sigma (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) : \sigma T_2
      • 1より
      • σΓσt:σT2\sigma \Gamma \vdash \sigma t : \sigma T_2
      • 2より
      • σΓσt:σT\sigma \Gamma \vdash \sigma t : \sigma T
    • したがって、所望の性質を満たす。
定理:制約型付けの健全性

(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解ならば、(Γ,t)(\Gamma, t) の解でもある。

概要:制約型付けの解は型付けの解でもある

証明:

定理の前提における導出 Γt:S  C\Gamma \vdash t : S ~ | ~ C に関する構造的帰納法によって示す。

  • CT-Varの場合、
    • 定理の前提における導出とCT-Varの結論を以下のように対応付ける。
      • t=xt = x (1)
    • 定理の前提より、(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解であるため
      • σS=T\sigma S = T (2)
    • 定理の前提およびCT-Varの前提より
      • x:SΓx : S \in \Gamma
      • 文脈に対する型代入の定義より
      • x:σSσΓx : \sigma S \in \sigma \Gamma
      • T-Varより
      • σΓx:σS\sigma \Gamma \vdash x : \sigma S
      • 2より
      • σΓx:T\sigma \Gamma \vdash x : T
      • 変数に対する型代入の定義より
      • σΓσx:T\sigma \Gamma \vdash \sigma x : T
      • 1より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。
  • CT-Absの場合、
    • 定理の前提における導出とCT-Absの結論を以下のように対応付ける。
      • t=λx:T1. t2t = \lambda x : T_1 . ~ t_2 (1)
      • S=T1T2S = T_1 \rightarrow T_2 (2)
    • 定理の前提より、(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解であるため
      • σ\sigmaCC を単一化する(3)
      • σS=T\sigma S = T
        • 2より
        • σ(T1T2)=T\sigma (T_1 \rightarrow T_2) = T
        • σT1σT2=T\sigma T_1 \rightarrow \sigma T_2 = T (4)
    • 定理の前提およびCT-Absの前提より
      • Γ,x:T1t2:T2  C\Gamma , x : T_1 \vdash t_2 : T_2 ~ | ~ C
      • 3より
      • (σ,σT2)(\sigma, \sigma T_2)((Γ,x:T1),t2,T2,C)((\Gamma , x : T_1), t_2, T_2, C) の解である
      • 帰納法の仮定より
      • (σ,σT2)(\sigma, \sigma T_2)((Γ,x:T1),t2)((\Gamma , x : T_1), t_2) の解である
      • 解の定義より
      • σ(Γ,x:T1)σt2:σT2\sigma (\Gamma , x : T_1) \vdash \sigma t_2 : \sigma T_2
      • σΓ,x:σT1σt2:σT2\sigma \Gamma , x : \sigma T_1 \vdash \sigma t_2 : \sigma T_2
      • T-Absより
      • σΓλx:σT1. σt2:σT1σT2\sigma \Gamma \vdash \lambda x : \sigma T_1 . ~ \sigma t_2 : \sigma T_1 \rightarrow \sigma T_2
      • 4より
      • σΓλx:σT1. σt2:T\sigma \Gamma \vdash \lambda x : \sigma T_1 . ~ \sigma t_2 : T
      • σΓσ(λx:T1. t2):T\sigma \Gamma \vdash \sigma (\lambda x : T_1 . ~ t_2) : T
      • 1より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。
  • CT-Appの場合、
    • 定理の前提における導出とCT-Appの結論を以下のように対応付ける。
      • t=t1 t2t = t_1 ~ t_2 (1)
      • S=XS = X (2)
      • C=C1C2{T1=T2X}C = C_1 \cup C_2 \cup \{T_1 = T_2 \rightarrow X\} (3)
    • 定理の前提より、(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解であるため
      • σ\sigmaCC を単一化する。3より
        • σ\sigmaC1C_1 を単一化する(4)
        • σ\sigmaC2C_2 を単一化する(5)
        • σ\sigma{T1=T2X}\{T_1 = T_2 \rightarrow X\} を単一化する
          • σT1=σ(T2X)\sigma T_1 = \sigma (T_2 \rightarrow X)
          • σT1=σT2σX\sigma T_1 = \sigma T_2 \rightarrow \sigma X (6)
      • σS=T\sigma S = T
        • 2より
        • σX=T\sigma X = T(7)
    • 定理の前提およびCT-Appの前提より
      • Γt1:T1  C1\Gamma \vdash t_1 : T_1 ~ | ~ C_1
      • 4より
      • (σ,σT1)(\sigma, \sigma T_1)(Γ,t1,T1,C1)(\Gamma, t_1, T_1, C_1) の解である
      • 帰納法の仮定より
      • (σ,σT1)(\sigma, \sigma T_1)(Γ,t1)(\Gamma, t_1) の解である
      • 解の定義より
      • σΓσt1:σT1\sigma \Gamma \vdash \sigma t_1 : \sigma T_1
      • 6より
      • σΓσt1:σT2σX\sigma \Gamma \vdash \sigma t_1 : \sigma T_2 \rightarrow \sigma X (8)
    • 定理の前提およびCT-Appの前提より
      • Γt2:T2  C2\Gamma \vdash t_2 : T_2 ~ | ~ C_2
      • 5より
      • (σ,σT2)(\sigma, \sigma T_2)(Γ,t2,T2,C2)(\Gamma, t_2, T_2, C_2) の解である
      • 帰納法の仮定より
      • (σ,σT2)(\sigma, \sigma T_2)(Γ,t2)(\Gamma, t_2) の解である
      • 解の定義より
      • σΓσt2:σT2\sigma \Gamma \vdash \sigma t_2 : \sigma T_2 (9)
    • 8、9、T-Appより
      • σΓσt1 σt2:σX\sigma \Gamma \vdash \sigma t_1 ~ \sigma t_2 : \sigma X
      • 7より
      • σΓσt1 σt2:T\sigma \Gamma \vdash \sigma t_1 ~ \sigma t_2 : T
      • σΓσ(t1 t2):T\sigma \Gamma \vdash \sigma (t_1 ~ t_2) : T
      • 1より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。
  • CT-Zeroの場合、
    • 定理の前提における導出とCT-Zeroの結論を以下のように対応付ける。
      • t=0t = 0 (1)
      • S=NatS = \text{Nat} (2)
    • 定理の前提より
      • σS=T\sigma S = T (3)
    • T-Zeroより
      • Γ0:Nat\Gamma \vdash 0 : \text{Nat}
      • 1より
      • Γt:Nat\Gamma \vdash t : \text{Nat}
      • 2より
      • Γt:S\Gamma \vdash t : S
      • 型代入の下での型付けの保存定理より
      • σΓσt:σS\sigma \Gamma \vdash \sigma t : \sigma S
      • 3より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。
  • CT-Succの場合、
    • 定理の前提における導出とCT-Succの結論を以下のように対応付ける。
      • t=succ t1t = \text{succ} ~ t_1 (1)
      • S=NatS = \text{Nat} (2)
      • C=C{T=Nat}C = C' \cup \{T' = \text{Nat}\} (3)
    • 定理の前提より、(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解であるため
      • σ\sigmaCC を単一化する。3より
        • σ\sigmaCC' を単一化する(4)
        • σ\sigma{T=Nat}\{T' = \text{Nat}\} を単一化する
          • σT=σNat\sigma T' = \sigma \text{Nat}
          • σT=Nat\sigma T' = \text{Nat} (5)
      • σS=T\sigma S = T
        • 2より
        • σNat=T\sigma \text{Nat} = T
        • Nat=T\text{Nat} = T (6)
    • 定理の前提およびCT-Succの前提より
      • Γt1:T  C\Gamma \vdash t_1 : T' ~ | ~ C'
      • 4より
      • (σ,σT)(\sigma, \sigma T')(Γ,t1,T,C)(\Gamma, t_1, T', C') の解である
      • 帰納法の仮定より
      • (σ,σT)(\sigma, \sigma T')(Γ,t1)(\Gamma, t_1) の解である
      • 解の定義より
      • σΓσt1:σT\sigma \Gamma \vdash \sigma t_1 : \sigma T'
      • 5より
      • σΓσt1:Nat\sigma \Gamma \vdash \sigma t_1 : \text{Nat}
      • T-Succより
      • σΓsucc (σt1):Nat\sigma \Gamma \vdash \text{succ} ~ (\sigma t_1) : \text{Nat}
      • σΓσ(succ t1):Nat\sigma \Gamma \vdash \sigma (\text{succ} ~ t_1) : \text{Nat}
      • 1より
      • σΓσt:Nat\sigma \Gamma \vdash \sigma t : \text{Nat}
      • 6より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。
  • CT-Letの場合、
    • 定理の前提における導出とCT-Letの結論を以下のように対応付ける。
      • t=(let x = t1 in t2)t = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) (1)
      • S=T2S = T_2 (2)
      • C=C1C2{T1=X}C = C_1 \cup C_2 \cup \{T_1 = X\} (3)
    • 定理の前提より、(σ,T)(\sigma, T)(Γ,t,S,C)(\Gamma, t, S, C) の解であるため
      • σ\sigmaCC を単一化する。3より
        • σ\sigmaC1C_1 を単一化する (4)
        • σ\sigmaC2C_2 を単一化する (5)
        • σ\sigma{T1=X}\{T_1 = X\} を単一化する
          • σT1=σX\sigma T_1 = \sigma X (6)
      • σS=T\sigma S = T
        • 2より
        • σT2=T\sigma T_2 = T (7)
    • 定理の前提およびCT-Letの前提より
      • Γt1:T1  C1\Gamma \vdash t_1 : T_1 ~ | ~ C_1
      • 4より
      • (σ,σT1)(\sigma, \sigma T_1)(Γ,t1,T1,C1)(\Gamma, t_1, T_1, C_1) の解である
      • 帰納法の仮定より
      • (σ,σT1)(\sigma, \sigma T_1)(Γ,t1)(\Gamma, t_1) の解である
      • 解の定義より
      • σΓσt1:σT1\sigma \Gamma \vdash \sigma t_1 : \sigma T_1 (8)
    • 定理の前提およびCT-Letの前提より
      • Γ,x:Xt2:T2  C2\Gamma , x : X \vdash t_2 : T_2 ~ | ~ C_2
      • 5より
      • (σ,σT2)(\sigma, \sigma T_2)((Γ,x:X),t2,T2,C2)((\Gamma , x : X), t_2, T_2, C_2) の解である
      • 帰納法の仮定より
      • (σ,σT2)(\sigma, \sigma T_2)((Γ,x:X),t2)((\Gamma , x : X), t_2) の解である
      • 解の定義より
      • σ(Γ,x:X)σt2:σT2\sigma (\Gamma , x : X) \vdash \sigma t_2 : \sigma T_2
      • σΓ,x:σXσt2:σT2\sigma \Gamma , x : \sigma X \vdash \sigma t_2 : \sigma T_2
      • 6より
      • σΓ,x:σT1σt2:σT2\sigma \Gamma , x : \sigma T_1 \vdash \sigma t_2 : \sigma T_2 (9)
    • 8、9とT-Letより
      • σΓlet x = σt1 in σt2:σT2\sigma \Gamma \vdash \text{let} ~ x ~ \text{=} ~ \sigma t_1 ~ \text{in} ~ \sigma t_2 : \sigma T_2
      • σΓσ(let x = t1 in t2):σT2\sigma \Gamma \vdash \sigma (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) : \sigma T_2
      • 1より
      • σΓσt:σT2\sigma \Gamma \vdash \sigma t : \sigma T_2
      • 7より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
    • したがって、(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解でもあるため、所望の結論を満たす。

定義:σ\sigma のそれぞれの組 XTX \mapsto T について、XχX \in \chi である組を除いた型代入を σ\χ\sigma \backslash \chi と書く。

定理:制約型付けの完全性

(σ,T)(\sigma, T)(Γ,t)(\Gamma, t) の解かつ、dom(σ)χ=dom(\sigma) \cap \chi = \varnothing ならば、σ\χ=σ\sigma' \backslash \chi = \sigma となるような (Γ,t,S,C)(\Gamma, t, S, C) の解 (σ,T)(\sigma', T) が存在する。

ただし、χ\chi は制約型付けによって導入される型変数の集合。

概要:型付けの解は、その型代入に「制約型付けによって導入される型変数に具体的な型を割り当てる組」を追加することで、制約型付けの解にできる。

証明:

定理の前提における導出 σΓσt:T\sigma \Gamma \vdash \sigma t : T に関する構造的帰納法による。

  • T-Varの場合、
    • 定理の前提における導出とT-Varの結論を以下のように対応付ける
      • σt=x\sigma t = x
        • 型代入は項の形に影響しない。したがって、型代入を適用して変数 xx となるのはそれ自身だけであるため
        • t=xt = x (1)
    • SS を以下のように定義する
      • T=σST = \sigma S (2)
    • 定理の前提における導出より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
      • 1より
      • σΓσx:T\sigma \Gamma \vdash \sigma x : T
      • σΓx:T\sigma \Gamma \vdash x : T
      • 逆転補題1より
      • x:TσΓx : T \in \sigma \Gamma
      • 2より
      • x:σSσΓx : \sigma S \in \sigma \Gamma
      • x:SΓx : S \in \Gamma
      • CT-Varより
      • Γx:S  {}\Gamma \vdash x : S ~ | ~ \{\}
      • CT-Varは型変数を導入しないため χ={}\chi = \{\} である。σ\sigma'SSCC を以下のように定義する
        • σ\χ=σ\sigma' \backslash \chi = \sigma (3)
          • χ\chi は空であるため
          • σ=σ\sigma' = \sigma (4)
        • C={}C = \{\}
          • CC が空であるため、σ\sigma'CC を単一化する (5)
      • Γx:S  C\Gamma \vdash x : S ~ | ~ C
      • 1より
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (6)
    • 2と4より
      • T=σST = \sigma' S (7)
    • 3、6、7、5より、所望の結論を満たす。
  • T-Absの場合、
    • 定理の前提における導出とT-Absの結論を以下のように対応付ける
      • σt=λx:T1. t2\sigma t = \lambda x : T_1 . ~ t_2 (1)
        • T1T'_1t2t'_2 を以下のように定義すると
          • σT1=T1\sigma T'_1 = T_1 (2)
          • σt2=t2\sigma t'_2 = t_2 (3)
        • t=λx:T1. t2t = \lambda x : T'_1 . ~ t'_2 (4)
      • T=T1T2T = T_1 \rightarrow T_2 (5)
    • 定理の前提における導出より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
      • 1より
      • σΓλx:T1. t2:T\sigma \Gamma \vdash \lambda x : T_1 . ~ t_2 : T
      • 5と逆転補題2より
      • σΓ,x:T1t2:T2\sigma \Gamma , x : T_1 \vdash t_2 : T_2
      • 2、3より
      • σΓ,x:σT1σt2:T2\sigma \Gamma , x : \sigma T'_1 \vdash \sigma t'_2 : T_2
      • σ(Γ,x:T1)σt2:T2\sigma (\Gamma , x : T'_1) \vdash \sigma t'_2 : T_2
      • (σ,T2)(\sigma, T_2)((Γ,x:T1),t2)((\Gamma , x : T'_1), t'_2) の解である
      • 帰納法の仮定より、ある σ1\sigma_1S2S_2C1C_1χ1\chi_1 について以下を満たす。ただし、χ1\chi_1 の要素はいずれもフレッシュに選ばれるものと仮定する
        • メモ:χ1\chi_1 がフレッシュに選ばれるため、帰納法の仮定を適用するための dom(σ)χ1=dom(\sigma) \cap \chi_1 = \varnothing はいつでも満たせる。
        • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma (6)
        • (σ1,T2)(\sigma_1, T_2)((Γ,x:T1),t2,S2,C1)((\Gamma , x : T'_1), t'_2, S_2, C_1) の解である
          • 解の定義より
            • Γ,x:T1t2:S2  C1\Gamma , x : T'_1 \vdash t'_2 : S_2 ~ | ~ C_1 (7)
            • σ1S2=T2\sigma_1 S_2 = T_2 (8)
            • σ1\sigma_1C1C_1 を単一化する (9)
    • 7より
      • Γ,x:T1t2:S2  C1\Gamma , x : T'_1 \vdash t'_2 : S_2 ~ | ~ C_1
      • CT-Absより
      • Γλx:T1. t2:T1S2  C1\Gamma \vdash \lambda x : T'_1 . ~ t'_2 : T'_1 \rightarrow S_2 ~ | ~ C_1
      • 4より
      • Γt:T1S2  C1\Gamma \vdash t : T'_1 \rightarrow S_2 ~ | ~ C_1
      • SSCC を以下のように定義する
        • S=T1S2S = T'_1 \rightarrow S_2 (10)
        • C=C1C = C_1 (11)
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (12)
    • χ\chiσ\sigma' を以下のように定義する
      • χ=χ1\chi = \chi_1 (13)
      • σ=σ1\sigma' = \sigma_1 (14)
    • 10より
      • S=T1S2S = T'_1 \rightarrow S_2
      • σ1S=σ1(T1S2)\sigma_1 S = \sigma_1 (T'_1 \rightarrow S_2)
      • σ1S=σ1T1σ1S2\sigma_1 S = \sigma_1 T'_1 \rightarrow \sigma_1 S_2
      • 8より
      • σ1S=σ1T1T2\sigma_1 S = \sigma_1 T'_1 \rightarrow T_2
      • 6と以下の議論より
        • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma
        • σ1\χ1(T1)=σT1\sigma_1 \backslash \chi_1 (T'_1) = \sigma T'_1
        • χ1\chi_1 の要素はフレッシュに選ばれているため、T1T'_1 内の型変数は χ1\chi_1 に含まれないことから
        • σ1T1=σT1\sigma_1 T'_1 = \sigma T'_1
      • σ1S=σT1T2\sigma_1 S = \sigma T'_1 \rightarrow T_2
      • 2より
      • σ1S=T1T2\sigma_1 S = T_1 \rightarrow T_2
      • 5より
      • σ1S=T\sigma_1 S = T
      • 14より
      • σS=T\sigma' S = T (15)
    • 6、13、14より
      • σ\χ=σ\sigma' \backslash \chi = \sigma (16)
    • 9、14、11より
      • σ\sigma'CC を単一化する (17)
    • 16、12、15、17より、所望の結論を満たす。
  • T-Appの場合、
    • 定理の前提における導出とT-Appの結論を以下のように対応付ける
      • σt=t1 t2\sigma t = t_1 ~ t_2 (1)
        • t1t'_1t2t'_2 を以下のように定義すると
          • σt1=t1\sigma t'_1 = t_1 (2)
          • σt2=t2\sigma t'_2 = t_2 (3)
        • t=t1 t2t = t'_1 ~ t'_2 (4)
      • T=T12T = T_{12} (5)
    • 定理の前提における導出より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
      • 1より
      • σΓt1 t2:T\sigma \Gamma \vdash t_1 ~ t_2 : T
      • 2、3より
      • σΓσt1 σt2:T\sigma \Gamma \vdash \sigma t'_1 ~ \sigma t'_2 : T
      • 5より
      • σΓσt1 σt2:T12\sigma \Gamma \vdash \sigma t'_1 ~ \sigma t'_2 : T_{12}
      • 逆転補題3より、以下を満たす T11T_{11} が存在する
        • σΓσt1:T11T12\sigma \Gamma \vdash \sigma t'_1 : T_{11} \rightarrow T_{12} (6)
        • σΓσt2:T11\sigma \Gamma \vdash \sigma t'_2 : T_{11} (7)
    • 6より
      • (σ,T11T12)(\sigma, T_{11} \rightarrow T_{12})(Γ,t1)(\Gamma, t'_1) の解である
      • 帰納法の仮定より、ある σ1\sigma_1S1S_1C1C_1χ1\chi_1 について以下を満たす。ただし、χ1\chi_1 の要素はいずれもフレッシュに選ばれるものと仮定する
        • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma (8)
        • (σ1,T11T12)(\sigma_1, T_{11} \rightarrow T_{12})(Γ,t1,S1,C1)(\Gamma, t'_1, S_1, C_1) の解である
          • 解の定義より
            • Γt1:S1  C1\Gamma \vdash t'_1 : S_1 ~ | ~ C_1 (9)
            • σ1S1=T11T12\sigma_1 S_1 = T_{11} \rightarrow T_{12} (10)
            • σ1\sigma_1C1C_1 を単一化する (11)
    • 7より
      • (σ,T11)(\sigma, T_{11})(Γ,t2)(\Gamma, t'_2) の解である
      • 帰納法の仮定より、ある σ2\sigma_2S2S_2C2C_2χ2\chi_2 について以下を満たす。ただし、χ2\chi_2 の要素はいずれもフレッシュに選ばれるものと仮定する
        • σ2\χ2=σ\sigma_2 \backslash \chi_2 = \sigma
        • (σ1,T11)(\sigma_1, T_{11})(Γ,t2,S2,C2)(\Gamma, t'_2, S_2, C_2) の解である
          • 解の定義より
            • Γt2:S2  C2\Gamma \vdash t'_2 : S_2 ~ | ~ C_2 (12)
            • σ2S2=T11\sigma_2 S_2 = T_{11} (13)
            • σ2\sigma_2C2C_2 を単一化する
    • 9、12、フレッシュな型変数 XX およびCT-Appにより
      • Γt1 t2:X  C1C2{S1=S2X}\Gamma \vdash t'_1 ~ t'_2 : X ~ | ~ C_1 \cup C_2 \cup \{S_1 = S_2 \rightarrow X\}
      • 4より
      • Γt:X  C1C2{S1=S2X}\Gamma \vdash t : X ~ | ~ C_1 \cup C_2 \cup \{S_1 = S_2 \rightarrow X\}
      • SSCC を以下のように定義する
        • S=XS = X (14)
        • C=C1C2{S1=S2X}C = C_1 \cup C_2 \cup \{S_1 = S_2 \rightarrow X\}
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (15)
    • χ\chi を以下のように定義する
      • χ=χ1χ2{X}\chi = \chi_1 \cup \chi_2 \cup \{X\} (16)
    • σ\sigma' を以下のように定義する
      • XTX \mapsto T (17)
      • YUY \mapsto U、ただし Yχ1Y \in \chi_1 かつ (YU)σ1(Y \mapsto U) \in \sigma_1 の場合 (18)
      • YUY \mapsto U、ただし Yχ2Y \in \chi_2 かつ (YU)σ2(Y \mapsto U) \in \sigma_2 の場合
      • YUY \mapsto U、ただし YχY \notin \chi かつ (YU)σ(Y \mapsto U) \in \sigma の場合 (19)
    • 14より
      • S=XS = X
      • σS=σX\sigma' S = \sigma' X
      • 17より
      • σS=T\sigma' S = T (20)
    • 以下の議論より、σ\χ=σ\sigma' \backslash \chi = \sigma である (21)
      • σ\sigma' の定義より、σ\χ\sigma' \backslash \chi に含まれる組は、19で定義されるものだけである
      • そのような組は、 σ\sigma に含まれる、かつそのときに限り σ\sigma' にも含まれる
    • 以下の議論より、σ\sigma'CC を単一化する (22)
      • σ\sigma'C1C_1 を単一化する
        • χ2\chi_2 の要素および XX は、9の導出とは独立に、フレッシュに選ばれているため、C1C_1 の単一化に関与しない
        • したがって、C1C_1 の単一化に関与する組 YUY \mapsto U は、18または19で定義される、Yχ1Y \in \chi_1 または YχY \notin \chi であるものだけである
          • Yχ1Y \in \chi_1 である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' にも含まれる
            • これは、Yχ1Y \in \chi_1 という前提条件が、σ\sigma' の定義の4つの節のうち、18以外の条件を満たさないことからわかる
          • YχY \notin \chi である組は、σ\sigma に含まれる、かつそのときに限り σ\sigma' にも含まれる
            • ここで、16より Yχ1Y \notin \chi_1 である
            • その場合、8より σ1=σ\sigma_1 = \sigma である
            • したがって、YχY \notin \chi である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' にも含まれる
        • したがって、C1C_1 の単一化に関わる組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' にも含まれる
        • 11より、σ1\sigma_1C1C_1 を単一化するため、σ\sigma' もまた C1C_1 を単一化する
      • C1C_1 と同様の議論より、σ\sigma'C2C_2 を単一化する
      • σ\sigma'{S1=S2X}\{S_1 = S_2 \rightarrow X\} を単一化する
        • σ{S1=S2X}\sigma' \{S_1 = S_2 \rightarrow X\}
        • {σS1=σ(S2X)}\{\sigma' S_1 = \sigma' (S_2 \rightarrow X)\}
        • σS1=σ(S2X)\sigma' S_1 = \sigma' (S_2 \rightarrow X)
        • σS1=σS2σX\sigma' S_1 = \sigma' S_2 \rightarrow \sigma' X
        • 以下の議論より σS1=σ1S1\sigma' S_1 = \sigma_1 S_1 であるため
          • χ2\chi_2 の要素および XX はフレッシュに選ばれているため、これらの型変数は S1S_1 に現れない
          • したがって、S1S_1 に適用されうる組は、18または19で定義される、Yχ1Y \in \chi_1 または YχY \notin \chi であるものだけである
          • C1C_1 と同様の議論より、S1S_1 に適用されうる組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' にも含まれる
          • したがって、σS1=σ1S1\sigma' S_1 = \sigma_1 S_1
        • σ1S1=σS2σX\sigma_1 S_1 = \sigma' S_2 \rightarrow \sigma' X
        • σ1\sigma_1 と同様の議論により
        • σ1S1=σ2S2σX\sigma_1 S_1 = \sigma_2 S_2 \rightarrow \sigma' X
        • 10、13、17より
        • T11T12=T11TT_{11} \rightarrow T_{12} = T_{11} \rightarrow T
        • 5より
        • T11T12=T11T12T_{11} \rightarrow T_{12} = T_{11} \rightarrow T_{12}
        • したがって、σ\sigma'{S1=S2X}\{S_1 = S_2 \rightarrow X\} を単一化する
    • 21、15、20、22より、所望の結論を満たす。
  • T-Zeroの場合、
    • 定理の前提における導出とT-Appの結論を以下のように対応付ける
      • σt=0\sigma t = 0
        • 型代入は項の形に影響しないため、代入を適用して 00 になる項はそれ自身しか無いため
        • t=0t = 0 (1)
      • T=NatT = \text{Nat} (2)
    • CT-Zeroより
      • Γ0:Nat  {}\Gamma \vdash 0 : \text{Nat} ~ | ~ \{\}
      • 1より
      • Γt:Nat  {}\Gamma \vdash t : \text{Nat} ~ | ~ \{\}
      • CT-Zeroは型変数を導入しないため χ={}\chi = \{\} である。σ\sigma'SSCC を以下のように定義する
        • σ\χ=σ\sigma' \backslash \chi = \sigma (3)
        • S=NatS = \text{Nat} (4)
        • C={}C = \{\}
          • CC は空であるため、σ\sigma'CC を単一化する (5)
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (6)
    • 4より
      • S=NatS = \text{Nat}
      • σS=σNat\sigma' S = \sigma' \text{Nat}
      • σS=Nat\sigma' S = \text{Nat}
      • 2より
      • σS=T\sigma' S = T (7)
    • 3、6、5、7より、所望の結論を満たす。
  • T-Succの場合、
    • 定理の前提における導出とT-Succの結論を以下のように対応付ける
      • σt=succ t1\sigma t = \text{succ} ~ t_1 (1)
        • t1t'_1 を以下のように定義すると
          • σt1=t1\sigma t'_1 = t_1 (2)
        • t=succ t1t = \text{succ} ~ t'_1 (3)
      • T=NatT = \text{Nat} (4)
    • 定理の前提における導出より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
      • 1より
      • σΓsucc t1:T\sigma \Gamma \vdash \text{succ} ~ t_1 : T
      • 逆転補題5より
      • σΓt1:Nat\sigma \Gamma \vdash t_1 : \text{Nat}
      • 2より
      • σΓσt1:Nat\sigma \Gamma \vdash \sigma t'_1 : \text{Nat}
      • (σ,Nat)(\sigma, \text{Nat})(Γ,t1)(\Gamma, t'_1) の解である
      • 帰納法の仮定より、ある σ1\sigma_1S1S_1C1C_1χ1\chi_1 について以下を満たす。ただし、χ1\chi_1 の要素はいずれもフレッシュに選ばれるものと仮定する
        • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma (5)
        • (σ1,Nat)(\sigma_1, \text{Nat})(Γ,t1,S1,C1)(\Gamma, t'_1, S_1, C_1) の解である
          • 解の定義より
            • Γt1:S1  C1\Gamma \vdash t'_1 : S_1 ~ | ~ C_1 (6)
            • σ1S1=Nat\sigma_1 S_1 = \text{Nat} (7)
            • σ1\sigma_1C1C_1 を単一化する (8)
    • 6とCT-Succより
      • Γsucc t1:Nat  C1{S1=Nat}\Gamma \vdash \text{succ} ~ t'_1 : \text{Nat} ~ | ~ C_1 \cup \{ S_1 = \text{Nat} \}
      • 3より
      • Γt:Nat  C1{S1=Nat}\Gamma \vdash t : \text{Nat} ~ | ~ C_1 \cup \{ S_1 = \text{Nat} \}
      • SSCC を以下のように定義する
        • S=NatS = \text{Nat} (9)
        • C=C1{S1=Nat}C = C_1 \cup \{ S_1 = \text{Nat} \}
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (10)
    • χ\chi を以下のように定義する
      • χ=χ1\chi = \chi_1 (11)
    • σ\sigma' を以下のように定義する
      • σ=σ1\sigma' = \sigma_1 (12)
    • 5より
      • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma
      • 12より
      • σ\χ1=σ\sigma' \backslash \chi_1 = \sigma
      • 11より
      • σ\χ=σ\sigma' \backslash \chi = \sigma (13)
    • 以下の議論より、σ\sigma'CC を単一化する (14)
      • σ\sigma'C1C_1 を単一化する
        • 8より
        • σ1\sigma_1C1C_1 を単一化する
        • 12より
        • σ\sigma'C1C_1 を単一化する
      • σ\sigma'{S1=Nat}\{ S_1 = \text{Nat} \} を単一化する
        • σ{S1=Nat}\sigma' \{ S_1 = \text{Nat} \}
        • 12より
        • σ1{S1=Nat}\sigma_1 \{ S_1 = \text{Nat} \}
        • {σ1S1=σ1Nat}\{ \sigma_1 S_1 = \sigma_1 \text{Nat} \}
        • σ1S1=σ1Nat\sigma_1 S_1 = \sigma_1 \text{Nat}
        • 7より
        • Nat=Nat\text{Nat} = \text{Nat}
    • 9より
      • S=NatS = \text{Nat}
      • σS=σNat\sigma' S = \sigma' \text{Nat}
      • σS=Nat\sigma' S = \text{Nat}
      • 4より
      • σS=T\sigma' S = T (15)
    • 13、10、14、15より、所望の結論を満たす
  • T-Letの場合、
    • 定理の前提における導出とT-Succの結論を以下のように対応付ける
      • σt=(let x = t1 in t2)\sigma t = (\text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2) (1)
        • t1t'_1t2t'_2 を以下のように定義すると
          • σt1=t1\sigma t'_1 = t_1 (2)
          • σt2=t2\sigma t'_2 = t_2 (3)
        • t=(let x = t1 in t2)t = (\text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t'_2) (4)
      • T=T2T = T_2 (5)
    • 定理の前提における導出より
      • σΓσt:T\sigma \Gamma \vdash \sigma t : T
      • 1より
      • σΓlet x = t1 in t2:T\sigma \Gamma \vdash \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T
      • 5より
      • σΓlet x = t1 in t2:T2\sigma \Gamma \vdash \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2
      • 逆転補題6より、ある T1T_1 が存在して
        • σΓt1:T1\sigma \Gamma \vdash t_1 : T_1
          • 2より
          • σΓσt1:T1\sigma \Gamma \vdash \sigma t'_1 : T_1
          • (σ,T1)(\sigma, T_1)(Γ,t1)(\Gamma, t'_1) の解である
          • 帰納法の仮定より、ある σ1\sigma_1S1S_1C1C_1χ1\chi_1 が存在して以下が成り立つ。ただし、χ1\chi_1 の各要素はフレッシュに選ばれると仮定する。
            • σ1\χ1=σ\sigma_1 \backslash \chi_1 = \sigma (6)
            • (σ1,T1)(\sigma_1, T_1)(Γ,t1,S1,C1)(\Gamma, t'_1, S_1, C_1) の解である
              • 解の定義より
                • Γt1:S1  C1\Gamma \vdash t'_1 : S_1 ~ | ~ C_1 (7)
                • σ1S1=T1\sigma_1 S_1 = T_1 (8)
                • σ1\sigma_1C1C_1 を単一化する (9)
        • σ(Γ,x:T1)t2:T2\sigma (\Gamma , x : T_1) \vdash t_2 : T_2
          • 3より
          • σ(Γ,x:T1)σt2:T2\sigma (\Gamma , x : T_1) \vdash \sigma t'_2 : T_2
          • σX\sigma_X を以下のように定義する。型代入の下での型付けの保存定理によって
            • σX=[XT1]\sigma_X = [X \mapsto T_1]
              • ただし、XX はフレッシュに選ばれた型変数
          • σXσ(Γ,x:X)σXσt2:σXT2\sigma_X \circ \sigma (\Gamma , x : X) \vdash \sigma_X \circ \sigma t'_2 : \sigma_X T_2
          • XX はフレッシュに選ばれており、T2T_2 に現れないため
          • σXσ(Γ,x:X)σXσt2:T2\sigma_X \circ \sigma (\Gamma , x : X) \vdash \sigma_X \circ \sigma t'_2 : T_2
          • (σXσ,T2)(\sigma_X \circ \sigma, T_2)((Γ,x:X),t2)((\Gamma , x : X), t'_2) の解である
          • 帰納法の仮定より、ある σ2\sigma_2S2S_2C2C_2χ2\chi_2 が存在して以下が成り立つ。ただし、χ2\chi_2 の各要素はフレッシュに選ばれると仮定する。
            • σ2\χ2=σXσ\sigma_2 \backslash \chi_2 = \sigma_X \circ \sigma (10)
            • (σ2,T2)(\sigma_2, T_2)((Γ,x:X),t2,S2,C2)((\Gamma , x : X), t'_2, S_2, C_2) の解である
              • 解の定義より
                • Γ,x:Xt2:S2  C2\Gamma , x : X \vdash t'_2 : S_2 ~ | ~ C_2 (11)
                • σ2S2=T2\sigma_2 S_2 = T_2 (12)
                • σ2\sigma_2C2C_2 を単一化する (13)
    • 7、11、フレッシュな型変数 XX とCT-Letより
      • Γlet x = t1 in t2:S2  C1C2{S1=X}\Gamma \vdash \text{let} ~ x ~ \text{=} ~ t'_1 ~ \text{in} ~ t'_2 : S_2 ~ | ~ C_1 \cup C_2 \cup \{S_1 = X\}
      • 4より
      • Γt:S2  C1C2{S1=X}\Gamma \vdash t : S_2 ~ | ~ C_1 \cup C_2 \cup \{S_1 = X\}
      • SSCC を以下のように定義する
        • S=S2S = S_2 (14)
        • C=C1C2{S1=X}C = C_1 \cup C_2 \cup \{S_1 = X\} (15)
      • Γt:S  C\Gamma \vdash t : S ~ | ~ C (16)
    • χ\chi を以下のように定義する
      • χ=χ1χ2{X}\chi = \chi_1 \cup \chi_2 \cup \{X\}
    • σ\sigma' を以下のように定義する (17)
      • XT1X \mapsto T_1
      • YUY \mapsto U、ただし Yχ1Y \in \chi_1 かつ (YU)σ1(Y \mapsto U) \in \sigma_1 の場合
      • YUY \mapsto U、ただし Yχ2Y \in \chi_2 かつ (YU)σ2(Y \mapsto U) \in \sigma_2 の場合
      • YUY \mapsto U、ただし YχY \notin \chi かつ (YU)σ(Y \mapsto U) \in \sigma の場合
    • 以下の議論より、σ\χ=σ\sigma' \backslash \chi = \sigma (18)
      • 17より、σ\χ\sigma' \backslash \chi に含まれる組 YUY \mapsto U は、YχY \notin \chi であるため、最後の節でのみ定義される
      • そのような組は、 σ\sigma に含まれる、かつそのときに限り σ\sigma' にも含まれる
    • σ\sigma' の組 YUY \mapsto U について、以下が成り立つ (19)
      • XT1X \mapsto T_1 は、σ2\sigma_2σ\sigma' に含まれる
        • σ\sigma' に含まれるのは定義より明らかである。
        • σ2\sigma_2 に含まれることを確認する。10より σ2\χ2=σXσ\sigma_2 \backslash \chi_2 = \sigma_X \circ \sigma である。σX\sigma_X の定義より、組は右辺に含まれる。したがって左辺の σ2\χ2\sigma_2 \backslash \chi_2 にも含まれ、σ2\sigma_2 にも含まれる
      • Yχ1Y \in \chi_1 である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' に含まれる
        • 17の各節が排他的であることからわかる
      • Yχ2Y \in \chi_2 である組は、σ2\sigma_2 に含まれる、かつそのときに限り σ\sigma' に含まれる
      • YχY \notin \chi である組は、σ\sigma に含まれる、かつそのときに限り σ\sigma' に含まれる
        • ここで、Yχ1Y \notin \chi_1 かつ Yχ2Y \notin \chi_2 かつ YXY \neq X である。
        • そのため、そのような組に着目すれば
          • 6より σ1=σ\sigma_1 = \sigma である
          • 10より σ2=σ\sigma_2 = \sigma である
        • したがって、当該の組は σ1\sigma_1 に含まれる、かつそのときに限り σ2\sigma_2 に含まれる、かつそのときに限り σ\sigma' に含まれる
    • 以下の議論より、σS=T\sigma' S = T (20)
      • 12より
      • σ2S2=T2\sigma_2 S_2 = T_2
      • 以下の議論より
        • σ\sigma' の組 YUY \mapsto U について、19と以下の議論より
          • XT1X \mapsto T_1 は、σ2\sigma_2σ\sigma' に含まれる
          • Yχ1Y \in \chi_1 である組は、S2S_2 に適用されない
            • χ1\chi_1 の要素が11の導出とは独立に、フレッシュに選ばれているため
          • Yχ2Y \in \chi_2 である組は、定義より σ2\sigma_2 に含まれる、かつそのときに限り σ\sigma' に含まれる
          • YχY \notin \chi である組は、σ2\sigma_2 に含まれる、かつそのときに限り σ\sigma' に含まれる
        • したがって、σ2S2=σS2\sigma_2 S_2 = \sigma' S_2 である
      • σS2=T2\sigma' S_2 = T_2
      • 14、5より
      • σS=T\sigma' S = T
    • 以下の議論より、σ\sigma'CC を単一化する (21)
      • σ\sigma'C1C_1 を単一化する
        • 9より
        • σ1\sigma_1C1C_1 を単一化する
        • σ\sigma' の組 YUY \mapsto U について、19と以下の議論より
          • XT1X \mapsto T_1 は、C1C_1 の単一化に関与しない
            • XX は7の導出とは独立にフレッシュに選ばれたため
          • Yχ1Y \in \chi_1 である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' に含まれる
          • Yχ2Y \in \chi_2 である組は、C1C_1 の単一化に関与しない
            • χ2\chi_2 の各要素は7の導出とは独立にフレッシュに選ばれたため
          • YχY \notin \chi である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' に含まれる
        • σ\sigma'C1C_1 を単一化する
      • σ\sigma'C2C_2 を単一化する
        • 13より
        • σ2\sigma_2C2C_2 を単一化する
        • σ\sigma' の組 YUY \mapsto U について、と以下の議論より
          • XT1X \mapsto T_1 は、σ2\sigma_2σ\sigma' に含まれる
          • Yχ1Y \in \chi_1 である組は、C1C_1 の単一化に関与しない
          • Yχ2Y \in \chi_2 である組は、σ2\sigma_2σ\sigma' に含まれる
          • YχY \notin \chi である組は、σ2\sigma_2 に含まれる、かつそのときに限り σ\sigma' に含まれる
        • σ\sigma'C2C_2 を単一化する
      • σ\sigma'{S1=X}\{S_1 = X\} を単一化する
        • σ{S1=X}\sigma' \{S_1 = X\}
        • {σS1=σX}\{\sigma' S_1 = \sigma' X\}
        • σS1=σX\sigma' S_1 = \sigma' X
        • 17より
        • σS1=T1\sigma' S_1 = T_1
        • σ\sigma' の組 YUY \mapsto U について、と以下の議論より
          • XT1X \mapsto T_1 は、S1S_1 に適用されない
          • Yχ1Y \in \chi_1 である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' に含まれる
          • Yχ2Y \in \chi_2 である組は、S1S_1 に適用されない
          • YχY \notin \chi である組は、σ1\sigma_1 に含まれる、かつそのときに限り σ\sigma' に含まれる
        • σ1S1=T1\sigma_1 S_1 = T_1
        • 8より
        • T1=T1T_1 = T_1
    • 18、16、20、21より、所望の結論を見たす

というわけで、

定理:型付けと制約型付けの対応

(Γ,t)(\Gamma, t) の解が存在する、かつそのときに限り (Γ,t,S,C)(\Gamma, t, S, C) の解が存在する。

証明:

制約型付けの健全性、完全性定理より成り立つ。

となります。よかったよかった。

単一化

制約型付けで得られた制約集合を単一化する型代入を見つけるために、以下の単一化アルゴリズム unifyを使用します。

定義:unify

  • unify( CC ) =
    • if ( CC = {}\{\} )
      • return [][]
    • else
      • let {S=T}C=C\{S = T\} \cup C' = C in
      • if ( SS == TT )
        • return unify( CC' )
      • else if ( SS == XX && XFV(T)X \notin FV(T) )
        • return unify( [XT]C[X \mapsto T] C' ) \circ [XT][X \mapsto T]
      • else if ( TT == XX && XFV(S)X \notin FV(S) )
        • return unify( [XS]C[X \mapsto S] C' ) \circ [XS][X \mapsto S]
      • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
        • return unify( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} )
      • else
        • fail

以降は、unifyの性質について示していきます。

定理:停止性

ある CC について、unifyは失敗するか、型代入を返すことで停止する。

証明:

CC の次数 (m,n)(m, n) を定義する。

mmCC に含まれる異なる型変数の数である。例えば、{X=AA,A=Nat}\{X = A \rightarrow A, A = \text{Nat}\} に含まれる異なる型変数は XXAA であるため、mm は2である。

nnCC の等式の空白を除いた文字数である。例えば、{X=AA,A=Nat}\{X = A \rightarrow A, A = \text{Nat}\}nn は、X=A→AA=Nat の文字数を数えて10である。

以下の議論によって、unifyの各節は即座に停止するか CC の次数を辞書的に減らす。次数の辞書的順序は整礎であるため、これが停止尺度となる。

  • unify( CC ) =
    • if ( CC = {}\{\} )
      • return [][]
      • 即座に停止する
    • else
      • let {S=T}C=C\{S = T\} \cup C' = C in
      • if ( SS == TT )
        • return unify( CC' )
        • SSTT が型変数であり、それが CC' に現れない場合、次数の mm が減少する
        • それ以外の場合、次数の mm は変化しないが、nn が減少する
      • else if ( SS == XX && XFV(T)X \notin FV(T) )
        • return unify( [XT]C[X \mapsto T] C' ) \circ [XT][X \mapsto T]
        • XFV(T)X \notin FV(T) かつ [XT]C[X \mapsto T] C' であることから、XX が制約集合から消えるため、次数の mm が減少する
      • else if ( TT == XX && XFV(S)X \notin FV(S) )
        • return unify( [XS]C[X \mapsto S] C' ) \circ [XS][X \mapsto S]
        • 上記と同様
      • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
        • return unify( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} )
        • CC から取り出された等式Aと CC' へ新たに追加される等式Bを以下のように比較すると、次数の nn が減少するとわかる
          • 等式A:S1S2=T1T2S_1 \rightarrow S_2 = T_1 \rightarrow T_2
          • 等式B:S1=T1S2=T2S_1 = T_1 S_2 = T_2
      • else
        • fail
        • 即座に停止する
定理:単一化

unify ( CC ) =σ= \sigma ならば、σ\sigmaCC を単一化する。

証明:

unifyの再起呼び出し回数に関する数学的帰納法による。nn 回の再帰呼出しを行うunifyを unifyn\text{unify}_n と書く。

  • n=0n = 0 の場合、
    • unify0{unify_0} ( CC ) =
      • if ( CC = {}\{\} )
        • return [][]
        • CC は空であるため、空の型代入 [][]CC を単一化し、所望の結論を満たす
      • else
        • let {S=T}C=C\{S = T\} \cup C' = C in
        • if ( SS == TT )
          • 再帰呼出しを行うため、n=0n = 0 である前提を満たさず、所望の結論は自明に満たされる
        • else if ( SS == XX && XFV(T)X \notin FV(T) )
          • 前提を満たさない
        • else if ( TT == XX && XFV(S)X \notin FV(S) )
          • 前提を満たさない
        • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
          • 前提を満たさない
        • else
          • 失敗するため、定理の前提を満たさない
  • 任意の nn について定理を仮定し、n+1n + 1 の場合を示す
    • unifyn+1\text{unify}_{n + 1} ( CC ) =
      • if ( CC = {}\{\} )
        • return [][]
        • 再帰呼出しを行わないため、n+1n + 1 回の再帰呼出しを行う前提を満たさない
      • else
        • let {S=T}C=C\{S = T\} \cup C' = C in
        • if ( SS == TT )
          • return unifyn\text{unify}_n ( CC' )
          • 定理の前提、および帰納法の仮定より、unifyn\text{unify}_n ( CC' ) =σ= \sigma' かつ σ\sigma'CC' を単一化する
          • SSTT が等しいため、σ=σ\sigma = \sigma' とおくと、σ\sigmaCC を単一化し、所望の結論を満たす
        • else if ( SS == XX && XFV(T)X \notin FV(T) )
          • return unifyn\text{unify}_n ( [XT]C[X \mapsto T] C' ) \circ [XT][X \mapsto T]
          • 定理の前提、および帰納法の仮定より、unifyn\text{unify}_n ( [XT]C[X \mapsto T] C' ) =σ= \sigma' かつ σ\sigma'[XT]C[X \mapsto T] C' を単一化する
          • σ=σ[XT]\sigma = \sigma' \circ [X \mapsto T] とおくと、σ\sigma{X=T}C\{X = T\} \cup C'、つまり CC を単一化し、所望の結論を満たす
        • else if ( TT == XX && XFV(S)X \notin FV(S) )
          • return unifyn\text{unify}_n ( [XS]C[X \mapsto S] C' ) \circ [XS][X \mapsto S]
          • 上記と同様
        • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
          • return unifyn\text{unify}_n ( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} )
          • 定理の前提、および帰納法の仮定より、unifyn\text{unify}_n ( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} ) =σ= \sigma' かつ σ\sigma'C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} を単一化する
          • σ=σ\sigma = \sigma' とおく
          • σ\sigma{S1=T1,S2=T2}\{S_1 = T_1, S_2 = T_2\} を単一化するため、{S1S2=T1T2}\{S_1 \rightarrow S_2 = T_1 \rightarrow T_2\} も単一化する
          • したがって、σ\sigmaC{S1S2=T1T2}C' \cup \{S_1 \rightarrow S_2 = T_1 \rightarrow T_2\}、つまり CC も単一化するため、所望の結論を満たす
        • else
          • 失敗するため、定理の前提を満たさない

定義:型代入 σ\sigmaσ\sigma' について、σ=σσ\sigma' = \sigma'' \circ \sigma となるような σ\sigma'' が存在する場合、σ\sigmaσ\sigma' よりも限定的でないといい、σσ\sigma \sqsubseteq \sigma' と書く。

定理:主要単一化

σ\sigma'CC を単一化するならば、unify ( CC ) =σ= \sigma かつ σσ\sigma \sqsubseteq \sigma' である。

証明:

unifyの再起呼び出し回数に関する数学的帰納法による。nn 回の再帰呼出しを行うunifyを unifyn\text{unify}_n と書く。

  • n=0n = 0 の場合、
    • unify1\text{unify}_1 ( CC ) =
      • if ( CC = {}\{\} )
        • return [][]
        • 以下のようになる
          • C={}C = \{\}
          • unify ( CC ) =σ=[]= \sigma = []
        • σ\sigma' を任意の型代入と定義する。
        • CC は空であるため、σ\sigma'CC を単一化する (1)
        • 以下の議論より、σσ\sigma \sqsubseteq \sigma' (2)
          • σ=σ\sigma' = \sigma'
          • σ=σ[]\sigma' = \sigma' \circ []
          • σ=σσ\sigma' = \sigma' \circ \sigma
          • σσ\sigma \sqsubseteq \sigma'
        • 1、2より所望の結論を満たす
      • else
        • let {S=T}C=C\{S = T\} \cup C' = C in
        • if ( SS == TT )
          • 前提を満たさない
        • else if ( SS == XX && XFV(T)X \notin FV(T) )
          • 前提を満たさない
        • else if ( TT == XX && XFV(S)X \notin FV(S) )
          • 前提を満たさない
        • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
          • 前提を満たさない
        • else
          • 以下の議論により、所望の結論は自明に満たされる
            • S=XS = X の場合
              • 前節のelse ifの条件により、XFV(T)X \in FV(T)
                • SFV(T)S \in FV(T)
              • 前節のelse ifの条件により、STS \neq T
              • 以上より、TTSS を含む、より複合的な型である
              • この場合、型代入によって SS をどのような型に写像しても、TTSS 以上に複合的な型になる
              • したがって、S=TS = T は単一化できないため、定理の前提を満たさない
            • S=NatS = \text{Nat} の場合
              • T=XT = X の場合
                • 前節のelse ifの条件によりありえない
              • T=NatT = \text{Nat} の場合
                • 前節のelse ifの条件によりありえない
              • T=T1T2T = T_1 \rightarrow T_2 の場合
                • そのような等式は単一化できないため、定理の前提を満たさない
            • S=S1S2S = S_1 \rightarrow S_2 の場合
              • T=XT = X の場合
                • S=XS = X の場合の議論と同様に、定理の前提を満たさない
              • T=NatT = \text{Nat} の場合
                • そのような等式は単一化できないため、定理の前提を満たさない
              • T=T1T2T = T_1 \rightarrow T_2 の場合
                • 前節のelse ifの条件によりありえない
  • 任意の nn について定理を仮定し、n+1n + 1 の場合を示す
    • unifyn+1\text{unify}_{n + 1} ( CC ) =
      • if ( CC = {}\{\} )
        • 前提を満たさない
      • else
        • let {S=T}C=C\{S = T\} \cup C' = C in
        • if ( SS == TT )
          • return unifyn\text{unify}_n ( CC' )
          • σ\sigma'CC' を単一化することと、帰納法の仮定より、ある σn\sigma_n について
            • unifyn\text{unify}_n ( CC' ) =σn= \sigma_n
              • unifyn+1\text{unify}_{n + 1} ( CC ) =σn= \sigma_n (1)
            • σnσ\sigma_n \sqsubseteq \sigma' (2)
          • σ=σn\sigma = \sigma_n とおくと、1、2より
            • unifyn+1\text{unify}_{n + 1} ( CC ) =σ= \sigma (3)
            • σσ\sigma \sqsubseteq \sigma' (4)
          • 3、4より、所望の結論を満たす
        • else if ( SS == XX && XFV(T)X \notin FV(T) )
          • return unifyn\text{unify}_n ( [XT]C[X \mapsto T] C' ) \circ [XT][X \mapsto T]
          • 定理の前提より
            • σ\sigma'CC を単一化する
            • S=TS = TCC の部分であるため
            • σ\sigma'S=TS = T を単一化する
            • 単一化の定義より
            • σS=σT\sigma' S = \sigma' T
            • ifの前提より
            • σX=σT\sigma' X = \sigma' T (1)
          • 定理の前提より
            • σ\sigma'CC を単一化する
            • CC'CC の部分であるため
            • σ\sigma'CC' を単一化する
            • 単一化の定義より、U1=U2CU_1 = U_2 \in C' とすると
            • σU1=σU2\sigma' U_1 = \sigma' U_2
            • 1より
            • σ([XT]U1)=σ([XT]U2)\sigma' ([X \mapsto T] U_1) = \sigma' ([X \mapsto T] U_2)
            • 単一化の定義より
            • σ\sigma'[XT]C[X \mapsto T] C' を単一化する (2)
          • 2と帰納法の仮定より、ある σn\sigma_n について
            • unifyn\text{unify}_n ( [XT]C[X \mapsto T] C' ) =σn= \sigma_n (3)
            • σnσ\sigma_n \sqsubseteq \sigma'
              • また、ある σn\sigma_n'' について
              • σ=σnσn\sigma' = \sigma_n'' \circ \sigma_n (4)
          • 3とunifyの定義より
            • unifyn+1\text{unify}_{n + 1} ( CC ) =σ= \sigma (5)
            • σ=σn[XT]\sigma = \sigma_n \circ [X \mapsto T] (6)
          • 以下の議論より σσ\sigma \sqsubseteq \sigma' である (7)
            • ある型変数 YY について
              • Y=XY = X の場合
                • 4より
                • σ=σnσn\sigma' = \sigma_n'' \circ \sigma_n
                • σT=(σnσn)T\sigma' T = (\sigma_n'' \circ \sigma_n) T
                • 1より
                • σX=(σnσn)T\sigma' X = (\sigma_n'' \circ \sigma_n) T
                • σX=(σnσn)([XT]X)\sigma' X = (\sigma_n'' \circ \sigma_n) ([X \mapsto T] X)
                • σX=(σn(σn[XT]))X\sigma' X = (\sigma_n'' \circ (\sigma_n \circ [X \mapsto T])) X
                • 6より
                • σX=(σnσ)X\sigma' X = (\sigma_n'' \circ \sigma) X
                • σY=(σnσ)Y\sigma' Y = (\sigma_n'' \circ \sigma) Y
              • YXY \neq X の場合
                • 4より
                • σ=σnσn\sigma' = \sigma_n'' \circ \sigma_n
                • σY=(σnσn)Y\sigma' Y = (\sigma_n'' \circ \sigma_n) Y
                • σY=(σnσn)([XT]Y)\sigma' Y = (\sigma_n'' \circ \sigma_n) ([X \mapsto T] Y)
                • σY=(σn(σn[XT]))Y\sigma' Y = (\sigma_n'' \circ (\sigma_n \circ [X \mapsto T])) Y
                • 6より
                • σY=(σnσ)Y\sigma' Y = (\sigma_n'' \circ \sigma) Y
            • したがって、σ\sigma' が作用する任意の YY について
              • σY=(σnσ)Y\sigma' Y = (\sigma_n'' \circ \sigma) Y
              • σ=σnσ\sigma' = \sigma_n'' \circ \sigma
              • σσ\sigma \sqsubseteq \sigma'
            • 5、7より、所望の結論を満たす
        • else if ( TT == XX && XFV(S)X \notin FV(S) )
          • return unifyn\text{unify}_n ( [XS]C[X \mapsto S] C' ) \circ [XS][X \mapsto S]
          • 上記と同様
        • else if ( SS == (S1S2)(S_1 \rightarrow S_2) && TT == (T1T2)(T_1 \rightarrow T_2) )
          • return unifyn\text{unify}_n ( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} )
          • 定理の前提より
            • σ\sigma'CC を単一化する
            • CC'CC の部分であるため
              • σ\sigma'CC' を単一化する (1)
            • S1S2=T1T2S_1 \rightarrow S_2 = T_1 \rightarrow T_2CC の部分であるため
              • σ\sigma'S1S2=T1T2S_1 \rightarrow S_2 = T_1 \rightarrow T_2 を単一化する
              • 単一化の定義より
              • σ(S1S2)=σ(T1T2)\sigma' (S_1 \rightarrow S_2) = \sigma' (T_1 \rightarrow T_2)
              • σS1σS2=σT1σT2\sigma' S_1 \rightarrow \sigma' S_2 = \sigma' T_1 \rightarrow \sigma' T_2
              • 両辺を比較すると
                • σS1=σT1\sigma' S_1 = \sigma' T_1
                  • σ\sigma'S1=T1S_1 = T_1 を単一化する (2)
                • σS2=σT2\sigma' S_2 = \sigma' T_2
                  • σ\sigma'S2=T2S_2 = T_2 を単一化する (3)
          • 1、2、3より
            • σ\sigma'C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} を単一化する (4)
          • 4と帰納法の仮定より、ある σn\sigma_n について
            • unifyn\text{unify}_n ( C{S1=T1,S2=T2}C' \cup \{S_1 = T_1, S_2 = T_2\} ) =σn= \sigma_n (5)
            • σnσ\sigma_n \sqsubseteq \sigma' (6)
          • 5とunifyの定義より
            • unifyn+1\text{unify}_{n + 1} ( CC ) =σ= \sigma (7)
            • σ=σn\sigma = \sigma_n (8)
          • 6、8より
            • σσ\sigma \sqsubseteq \sigma' (9)
          • 7、9より、所望の結論を満たす
        • else
          • n=0n = 0 の場合の議論と同様に、所望の結論は自明に満たされる

というわけで、unifyは CC を充足する型代入を計算してくれます。しかも、その代入は最も限定的でないもので、アルゴリズムは必ず停止するという良い性質を備えています。やったね

練習

型推論がどのように行われるかを手計算で実感してみます。

TAPLの演習22.3.3を解いてみます。以下の項の型を推論します。

λx:X. λy:Y. λz:Z. (x z) (y z)\lambda x : X . ~ \lambda y : Y . ~ \lambda z : Z . ~ (x ~ z) ~ (y ~ z)

制約型付け導出は以下のようになります。

x:Xx:X,y:Y,z:Zx:X,y:Y,z:Z{A,B,C}x:X {A,B,C} {}(CT-Var)z:Zx:X,y:Y,z:Zx:X,y:Y,z:Z{A,B,C}z:Z {A,B,C} {}(CT-Var)x:X,y:Y,z:Z{A,B,C}(x z):A {B,C} {X=ZA}(CT-App)y:Yx:X,y:Y,z:Zx:X,y:Y,z:Z{B,C}y:Y {B,C} {}(CT-Var)z:Zx:X,y:Y,z:Zx:X,y:Y,z:Z{B,C}z:Z {B,C} {}(CT-Var)x:X,y:Y,z:Z{B,C}(y z):B {C} {Y=ZB}(CT-App)x:X,y:Y,z:Z{A,B,C}(x z) (y z):C {} {X=ZA,Y=ZB,A=BC}(CT-App)x:X,y:Y{A,B,C}λz:Z. (x z) (y z):ZC {} {X=ZA,Y=ZB,A=BC}(CT-Abs)x:X{A,B,C}λy:Y. λz:Z. (x z) (y z):Y(ZC) {} {X=ZA,Y=ZB,A=BC}(CT-Abs){A,B,C}λx:X. λy:Y. λz:Z. (x z) (y z):X(Y(ZC)) {} {X=ZA,Y=ZB,A=BC}(CT-Abs)\dfrac { \dfrac { \dfrac { \dfrac { \dfrac { \dfrac { x : X \in x : X , y : Y , z : Z } { x : X , y : Y , z : Z \vdash_{\{A , B , C\}} x : X ~ |_{\{A , B , C\}} ~ \{\} } \quad\text{(CT-Var)} \qquad \dfrac { z : Z \in x : X , y : Y , z : Z } { x : X , y : Y , z : Z \vdash_{\{A , B , C\}} z : Z ~ |_{\{A , B , C\}} ~ \{\} } \quad\text{(CT-Var)} } { x : X , y : Y , z : Z \vdash_{\{A , B , C\}} (x ~ z) : A ~ |_{\{B , C\}} ~ \{ X = Z \rightarrow A \} } \quad\text{(CT-App)} \qquad \dfrac { \dfrac { y : Y \in x : X , y : Y , z : Z } { x : X , y : Y , z : Z \vdash_{\{B , C\}} y : Y ~ |_{\{B , C\}} ~ \{\} } \quad\text{(CT-Var)} \qquad \dfrac { z : Z \in x : X , y : Y , z : Z } { x : X , y : Y , z : Z \vdash_{\{B , C\}} z : Z ~ |_{\{B , C\}} ~ \{\} } \quad\text{(CT-Var)} } { x : X , y : Y , z : Z \vdash_{\{B , C\}} (y ~ z) : B ~ |_{\{C\}} ~ \{ Y = Z \rightarrow B \} } \quad\text{(CT-App)} } { x : X , y : Y , z : Z \vdash_{\{A, B, C\}} (x ~ z) ~ (y ~ z) : C ~ |_{\{\}} ~ \{ X = Z \rightarrow A , Y = Z \rightarrow B , A = B \rightarrow C \} } \quad\text{(CT-App)} } { x : X , y : Y \vdash_{\{A, B, C\}} \lambda z : Z . ~ (x ~ z) ~ (y ~ z) : Z \rightarrow C ~ |_{\{\}} ~ \{ X = Z \rightarrow A , Y = Z \rightarrow B , A = B \rightarrow C \} } \quad\text{(CT-Abs)} } { x : X \vdash_{\{A, B, C\}} \lambda y : Y . ~ \lambda z : Z . ~ (x ~ z) ~ (y ~ z) : Y \rightarrow (Z \rightarrow C) ~ |_{\{\}} ~ \{ X = Z \rightarrow A , Y = Z \rightarrow B , A = B \rightarrow C \} } \quad\text{(CT-Abs)} } { \vdash_{\{A, B, C\}} \lambda x : X . ~ \lambda y : Y . ~ \lambda z : Z . ~ (x ~ z) ~ (y ~ z) : X \rightarrow (Y \rightarrow (Z \rightarrow C)) ~ |_{\{\}} ~ \{ X = Z \rightarrow A , Y = Z \rightarrow B , A = B \rightarrow C \} } \quad\text{(CT-Abs)}

めっちゃ横に長いです。幅の広い画面で見ている方は、

が役に立つかもしれません。リロードするともとに戻ります。

制約型付けで得られた制約を単一化アルゴリズムで解きます。

unify({X=ZA,Y=ZB,A=BC})=unify([XZA]{Y=ZB,A=BC})[XZA]=unify({Y=ZB,A=BC})[XZA]=unify([YZB]{A=BC})[YZB][XZA]=unify({A=BC})[YZB][XZA]=unify([ABC]{})[ABC][YZB][XZA]=unify({})[ABC][YZB][XZA]=[][ABC][YZB][XZA]\begin{aligned} & \text{unify} ( \{ X = Z \rightarrow A , Y = Z \rightarrow B , A = B \rightarrow C \} ) \\ &= \text{unify} ( [X \mapsto Z \rightarrow A] \{ Y = Z \rightarrow B , A = B \rightarrow C \} ) \circ [X \mapsto Z \rightarrow A] \\ &= \text{unify} ( \{ Y = Z \rightarrow B , A = B \rightarrow C \} ) \circ [X \mapsto Z \rightarrow A] \\ &= \text{unify} ( [Y \mapsto Z \rightarrow B] \{ A = B \rightarrow C \} ) \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] \\ &= \text{unify} ( \{ A = B \rightarrow C \} ) \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] \\ &= \text{unify} ( [A \mapsto B \rightarrow C] \{\} ) \circ [A \mapsto B \rightarrow C] \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] \\ &= \text{unify} ( \{\} ) \circ [A \mapsto B \rightarrow C] \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] \\ &= [] \circ [A \mapsto B \rightarrow C] \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] \\ \end{aligned}

主要型は以下のとおりです。

[][ABC][YZB][XZA](X(Y(ZC)))=[][ABC][YZB]((ZA)(Y(ZC)))=[][ABC]((ZA)((ZB)(ZC)))=[]((Z(BC))((ZB)(ZC)))=(Z(BC))((ZB)(ZC))\begin{aligned} & [] \circ [A \mapsto B \rightarrow C] \circ [Y \mapsto Z \rightarrow B] \circ [X \mapsto Z \rightarrow A] (X \rightarrow (Y \rightarrow (Z \rightarrow C))) \\ &= [] \circ [A \mapsto B \rightarrow C] \circ [Y \mapsto Z \rightarrow B] ((Z \rightarrow A) \rightarrow (Y \rightarrow (Z \rightarrow C))) \\ &= [] \circ [A \mapsto B \rightarrow C] ((Z \rightarrow A) \rightarrow ((Z \rightarrow B) \rightarrow (Z \rightarrow C))) \\ &= [] ((Z \rightarrow (B \rightarrow C)) \rightarrow ((Z \rightarrow B) \rightarrow (Z \rightarrow C))) \\ &= (Z \rightarrow (B \rightarrow C)) \rightarrow ((Z \rightarrow B) \rightarrow (Z \rightarrow C)) \\ \end{aligned}

これは以下のもともとの項に整合しているとわかります。

λx:X. λy:Y. λz:Z. (x z) (y z)\lambda x : X . ~ \lambda y : Y . ~ \lambda z : Z . ~ (x ~ z) ~ (y ~ z)

SICPの思い出

単一化アルゴリズムはSICPでも登場してました。あっちでは論理プログラミングにおける変数束縛で使われてましたね。パターンには値と変数がどちらも現れうるので、値と値の等式、値と変数の等式、変数と変数の等式の制約集合を解くために必要でした。

TAPLによれば、

実はこのアルゴリズムのどの部分も、単一化の対象が型式であることには依存していない。同じアルゴリズムを用いて、他の任意の種類の式(ただし一階のもの)に関する等式制約を解ける。

出典:定義22.4.4、型システム入門 プログラミング言語と型の理論

とあります。なーるほど。

実装

証明が終わったのでさっそく実装していきましょう。

構文解析

まず、どのようにプログラムを書くかという、具象構文を定義します。

Term ::=
  Identifier
  λIdentifier. Term
  Term Term
  0
  Succ Term
  let Identifier = Term in Term
  (Term)

Identifier ::=
  /[a-zA-Z0-9]+/

抽象構文に似ていますが、カッコの規則などが追加されています。

証明などの形式的な議論では明示的には不要でしたが、実際にプログラムを書く際には必要です。例えば、適用の優先順位を指定する際などに使います。

字句解析

勘で実装しました。

例えば、λhoge.という文字列の入力に対しては、

  • ラムダ記号
  • hogeというIdentifier
  • ドット記号

というトークンの列を出力します。

また、スペースの連続や改行、コメントの除去などもここで処理してくれます。

構文解析:LR法

前から興味があったLR法を実装してみました。

特にLR構文解析の原理という論文が最高なので人類の皆さんにおすすめです。

LR法に関する他の資料も参照したのですが、「アクション表やShift、Reduceを使ってそれが実行されるのはわかるけど、それでなぜ構文解析ができるのかがいまいち納得できない」という感じでした。

しかし上記の論文では、LR法が非決定性有限オートマトンを繰り返し使用することで実装できること、そして部分集合構成法を使用することで、非決定性有限オートマトンを決定性有限オートマトンに変換し、実行できることが順序良く示されていてわかりやすかったです。

あまりに良いので、日本ソフトウェア科学会の解説論文賞を受賞してたりするそうです。

大堀先生、ありがとうございました。

構文の実装

LR法のおかげで、構文を実装するのはとても楽になります。

例えば以下は適用の構文規則 Term ::= Term Term の実装です。

[
  // ...
  {
    symbol: "Term",
    expression: ["Term", "Spaces", "Term"],
    callback: (symbols): Result<ASTApply> => {
      const operator = symbols[0];
      const operand = symbols[2];
      if (!isAST(operator)) return error();
      if (!isAST(operand)) return error();

      return ok({ kind: "ast", type: "Apply", operator, operand });
    },
  },
  // ...
];

symbol: "Term"::= の左辺、 expression: ["Term", "Spaces", "Term"] が右辺に直接対応しています。

callback は、この規則がマッチしたときに呼ばれる関数で、 ["Term", "Spaces", "Term"] のトークン列から適用のASTノードを返します。

syntax.tsにはこのような規則が配列として列挙してあります。

パーサーはこの規則をもとにオートマトンを構築して、トークン列からASTを構築してくれます。便利ですね。

実際、見通しが甘くて文法の改修を何度か行ったのですが、とても短時間で済んでしまい驚きました。

評価器、型検査器

評価規則と制約型付けを愚直に実装しました。マジでそれだけです。

完成!

言語の名前はpico-lambdaとしました。1

型無しラムダ計算

とりあえず型検査はオフにして、まずは簡単な計算から

let ToNumber = λn. (n (λx. (succ x)) 0) in

let One   = λs. λz. (s z) in
let Two   = λs. λz. (s (s z)) in
let Three = λs. λz. (s (s (s z))) in
let Four  = λs. λz. (s (s (s (s z)))) in

// see: https://en.wikipedia.org/wiki/Church_encoding
let Succ = λn. λf. λx. (f (n f x)) in
let Plus = λm. λn. (m Succ n) in
let Mult = λm. λn. λf. (m (n f)) in
let Exp  = λm. λn. (n m) in
let Pred = λn. λf. λx. (n (λg. λh. (h (g f))) (λu. x) (λu. u)) in

(ToNumber
  // ((1 + 2) * 3)^(4 - 1) = 729
  (Exp
    (Mult (Plus One Two) Three)
    (Pred Four)
  )
)
$ ./main.ts examples/arithmetics.lambda --skip-tc
729

おー、計算できてます!

729 というのは、本当は succ (succ (... (succ 0) ...)) という値で、Printerがよしなに数字として表示しているだけです。

続いて、前回の記事でも触れたZコンビネータを使った階乗の計算

let ToNumber = λn. (n (λx. (succ x)) 0) in

let Zero = λs. λz. z in
let One = λs. λz. (s z) in
let Five = λs. λz. (s (s (s (s (s z))))) in

let Succ = λn. λs. λz. (s (n s z)) in

let Mul = λn1. λn2. λs. λz. (n2 (λz. (n1 s z)) z) in

let MakePair = λfirstValue. λsecondValue. λselector. (selector firstValue secondValue) in
let First = λpair. (pair (λfirstValue. λsecondValue. firstValue)) in
let Second = λpair. (pair (λfirstValue. λsecondValue. secondValue)) in
let Pred = λn. (
  (Second
    (n
      // s
      λpair. (
        (MakePair
          (Succ (First pair))
          (First pair)
        )
      )
      // z
      (MakePair Zero Zero)
    )
  )
) in

let Force = λthunk. (thunk 0) in

let If = λbool. λdelayedTrueValue. λdelayedFalseValue. (bool delayedTrueValue delayedFalseValue) in
let True = λdelayedTrueValue. λdelayedFalseValue. (Force delayedTrueValue) in
let False = λdelayedTrueValue. λdelayedFalseValue. (Force delayedFalseValue) in

let IsZero = λn. (n (λz. False) True) in

let Fix = (
  λg. (
    λh. (
      g (λarg. (h h arg))
    )
    λh. (
      g (λarg. (h h arg))
    )
  )
) in

// main
let Fact = (
  Fix
  λfact. λn. (
    (If
      (IsZero n)
      λx. One
      λx. (
        Mul
        n
        (fact (Pred n))
      )
    )
  )
) in

(ToNumber (Fact Five))
$ ./main.ts examples/fact.lambda --skip-tc
120

いいですね!

次は発散コンビネータ(omegaとも)、関数だけで無限ループするやつ

(λf. (f f)) (λf. (f f))
$ ./main.ts examples/omega.lambda --skip-tc
# 停止しない

ちゃんと動いてますねー

型付きラムダ計算

それでは、--skip-tc を外し、型検査を有効にして動かしてみます。

まず、先程の簡単な計算は以下のようになります。

$ ./main.ts examples/arithmetics.lambda
tc passed: Nat
729

型検査をパスして、推論の結果が Nat 型であると表示されています。検査をパスしたので、実際に実行してみたら 729 という値だったというわけです。このことは、これまでに示した一連の定理によって保証されています。

無限ループである発散コンビネータはどうなるでしょうか。

$ ./main.ts examples/omega.lambda
type checking failed
{
  msg: 'inferType: unification failed',
  error: { ... }
}

型検査に失敗したので、そもそも実行されませんでした。無限ループはいつまでも値にならないので、それに型は付かなさそうだというのは感覚的に納得できると思います。

全ての無限ループを生まれる前に消し去りたい ってやつです

実際、停止しないならば項に型は付かない(項に型が付くならば停止する)と言うには、停止性という性質を証明する必要があるそうです。型付きラムダ計算では停止性が成り立つと知られています。

ところで、同じような理由でZコンビネータにも型が付かないので、先程の階乗の計算もまた実行できません。

$ ./main.ts examples/fact.lambda
type checking failed
...

さすがにループが書けないのは実用上厳しいです。

この能力を取り戻すために、高度な型システムを組み込んだり、特殊な評価規則を追加したりすることによって、制限を緩める方法があるようです。

単相性

今回作った型システムは単相的です。以下のプログラムは型エラーになります。

let id = λx. x in

(
  id // 1
  id // 2
)

2の id を考えると AAA \rightarrow A 型が付きそうですが、 1の id を考えると (AA)(AA)(A \rightarrow A) \rightarrow (A \rightarrow A) 型でないとダメそうです。

CT-Letは、

ΓFt1:T1 F C1Γ,x:XFt2:T2 F C2F=X,FΓFlet x = t1 in t2:T2 F C1C2{T1=X}(CT-Let)\dfrac { \begin{aligned} & \Gamma \vdash_F t_1 : T_1 ~ |_{F'} ~ C_1 \\ & \Gamma , x : X \vdash_{F'} t_2 : T_2 ~ |_{F''} ~ C_2 \\ & F'' = X, F''' \end{aligned} } { \Gamma \vdash_F \text{let} ~ x ~ \text{=} ~ t_1 ~ \text{in} ~ t_2 : T_2 ~ |_{F'''} ~ C_1 \cup C_2 \cup \{T_1 = X\} } \quad\text{(CT-Let)}

としていました。

ここで、x=idx = id なので、文脈を Γ,id:X\Gamma , id : X として t2=(id id)t_2 = (id ~ id) の型を推論するのですが、どちらの idid も同一の XX とみなして制約を生成するので、最終的に単一化でエラーというわけです。

これを解消するには、例えば以下のように書けば良いのですが、

let id1 = λx. x in
let id2 = λx. x in

(id1 id2)

型の都合でプログラムが汚れているのでだいぶ嫌です。

これを解消する方法はいろいろあるようで、おそらく最も有名なのがLet多相です。気が向いたら組み込んでみたいですね。

まとめ

型のリハビリをしました。構文解析では、前から気になっていたLR法を実装しました。

型初心者なので、間違っている箇所がありそうです。見つけたら教えていただけると助かります。

それでは!

参考資料


  1. 社の先輩が作ったpico-mlという言語の名前に影響を受けています。

続けて読む…

TypeScriptの型で全加算器から浮動小数点数,そして√2

2021/06/07

BlenderとEeveeで地球

2021/08/11

Idrisでふんわり眺める依存型

2022/07/04

Advent of Code 2021攻略ガイド

2021/12/28

SICPの備忘録

2023/07/29

Linux kernelのMakefileを雰囲気で読んだ話

2020/04/28

書いた人

sititou70のアイコン画像
sititou70

都内の社会人エンジニア3年生。Web技術、3DCG、映像制作が好き。