Typechecking_J: STLCの型チェッカ¶
Require Export Stlc_J.
Require Import Relations.
STLCのhas_type関係は(あるコンテキストのもとで)項が型に属するという意味を定義します。しかし、それ自身では、項に型付けができるかどうかの「チェック方法」は与えません。
幸いにも、has_typeを定義する規則は構文指向(syntax directed)です。項の形にそのまま従います。このことから、型付け規則を型チェック「関数」の節にそのまま変換することができます。この関数は、項とコンテキストをとり、その項の型を返すか、項が型付けできないという信号を出します。
Module STLCChecker.
Import STLC.
型を比較する¶
最初に、2つの型の等しさを比較する関数が必要です...
Fixpoint beq_ty (T1 T2:ty) : bool :=
match T1,T2 with
| ty_Bool, ty_Bool =>
true
| ty_arrow T11 T12, ty_arrow T21 T22 =>
andb (beq_ty T11 T21) (beq_ty T12 T22)
| _,_ =>
false
end.
... そして、beq_tyが返すブール値の結果と2つの入力が等しいという論理命題との間の、通常の双方向結合を確立します。
Lemma beq_ty_refl : forall T1,
beq_ty T1 T1 = true.
Proof.
intros T1. induction T1; simpl.
reflexivity.
rewrite IHT1_1. rewrite IHT1_2. reflexivity. Qed.
Lemma beq_ty__eq : forall T1 T2,
beq_ty T1 T2 = true -> T1 = T2.
Proof with auto.
intros T1. induction T1; intros T2 Hbeq; destruct T2; inversion Hbeq.
Case "T1=ty_Bool".
reflexivity.
Case "T1=ty_arrow T1_1 T1_2".
apply andb_true in H0. destruct H0 as [Hbeq1 Hbeq2].
apply IHT1_1 in Hbeq1. apply IHT1_2 in Hbeq2. subst... Qed.
型チェッカ¶
そしてこれが型チェッカです。与えられた項の構造をたどって調べ、Some TまたはNoneを返します。部分項の型を調べるために再帰呼び出しをするたびに、結果についてパターンマッチをして、Noneでないことを確認します。tm_appの場合はさらに、パターンマッチングで関数型の矢印の右側と左側を抽出します(そして関数の型がty_arrow T11 T12という形ではないときは失敗します(つまりNoneを返します))。
Fixpoint type_check (Gamma:context) (t:tm) : option ty :=
match t with
| tm_var x => Gamma x
| tm_abs x T11 t12 => match type_check (extend Gamma x T11) t12 with
| Some T12 => Some (ty_arrow T11 T12)
| _ => None
end
| tm_app t1 t2 => match type_check Gamma t1, type_check Gamma t2 with
| Some (ty_arrow T11 T12),Some T2 =>
if beq_ty T11 T2 then Some T12 else None
| _,_ => None
end
| tm_true => Some ty_Bool
| tm_false => Some ty_Bool
| tm_if x t f => match type_check Gamma x with
| Some ty_Bool =>
match type_check Gamma t, type_check Gamma f with
| Some T1, Some T2 =>
if beq_ty T1 T2 then Some T1 else None
| _,_ => None
end
| _ => None
end
end.
性質¶
この型チェックアルゴリズムが正しいことを検証するため、この関数がオリジナルのhas_type関係について健全(sound)で完全(complete)であることを示します。つまり、type_checkとhas_typeが同じ部分関数を定義することです。
Theorem type_checking_sound : forall Gamma t T,
type_check Gamma t = Some T -> has_type Gamma t T.
Proof with eauto.
intros Gamma t. generalize dependent Gamma.
tm_cases (induction t) Case; intros Gamma T Htc; inversion Htc.
Case "tm_var"...
Case "tm_app".
remember (type_check Gamma t1) as TO1.
remember (type_check Gamma t2) as TO2.
destruct TO1 as [T1|]; try solve by inversion;
destruct T1 as [|T11 T12]; try solve by inversion.
destruct TO2 as [T2|]; try solve by inversion.
remember (beq_ty T11 T2) as b.
destruct b; try solve by inversion.
symmetry in Heqb. apply beq_ty__eq in Heqb.
inversion H0; subst...
Case "tm_abs".
rename i into y. rename t into T1.
remember (extend Gamma y T1) as G'.
remember (type_check G' t0) as TO2.
destruct TO2; try solve by inversion.
inversion H0; subst...
Case "tm_true"...
Case "tm_false"...
Case "tm_if".
remember (type_check Gamma t1) as TOc.
remember (type_check Gamma t2) as TO1.
remember (type_check Gamma t3) as TO2.
destruct TOc as [Tc|]; try solve by inversion.
destruct Tc; try solve by inversion.
destruct TO1 as [T1|]; try solve by inversion.
destruct TO2 as [T2|]; try solve by inversion.
remember (beq_ty T1 T2) as b.
destruct b; try solve by inversion.
symmetry in Heqb. apply beq_ty__eq in Heqb.
inversion H0. subst. subst...
Qed.
Theorem type_checking_complete : forall Gamma t T,
has_type Gamma t T -> type_check Gamma t = Some T.
Proof with auto.
intros Gamma t T Hty.
has_type_cases (induction Hty) Case; simpl.
Case "T_Var"...
Case "T_Abs". rewrite IHHty...
Case "T_App".
rewrite IHHty1. rewrite IHHty2.
rewrite (beq_ty_refl T11)...
Case "T_True"...
Case "T_False"...
Case "T_If". rewrite IHHty1. rewrite IHHty2.
rewrite IHHty3. rewrite (beq_ty_refl T)...
Qed.
End STLCChecker.