Typechecking
The has_type relation of the STLC defines what it means for a
term to belong to a type (in some context). But it doesn't, by
itself, tell us how to check whether or not a term is well
typed.
Fortunately, the rules defining has_type are syntax directed
— they exactly follow the shape of the term. This makes it
straightforward to translate the typing rules into clauses of a
typechecking function that takes a term and a context and either
returns the term's type or else signals that the term is not
typable.
Fixpoint beq_ty (T1 T2:ty) : bool :=
match T1,T2 with
| TBool, TBool ⇒
true
| TArrow T11 T12, TArrow T21 T22 ⇒
andb (beq_ty T11 T21) (beq_ty T12 T22)
| _,_ ⇒
false
end.
... and we need to establish the usual two-way connection between
the boolean result returned by beq_ty and the logical
proposition that its inputs are equal.
Lemma beq_ty_refl : ∀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 : ∀T1 T2,
beq_ty T1 T2 = true → T1 = T2.
Proof with auto.
intros T1. induction T1; intros T2 Hbeq; destruct T2; inversion Hbeq.
- (* T1=TBool *)
reflexivity.
- (* T1=TArrow T1_1 T1_2 *)
rewrite andb_true_iff in H0. inversion H0 as [Hbeq1 Hbeq2].
apply IHT1_1 in Hbeq1. apply IHT1_2 in Hbeq2. subst... Qed.
The Typechecker
Fixpoint type_check (Γ:context) (t:tm) : option ty :=
match t with
| tvar x ⇒ Γ x
| tabs x T11 t12 ⇒ match type_check (update Γ x T11) t12 with
| Some T12 ⇒ Some (TArrow T11 T12)
| _ ⇒ None
end
| tapp t1 t2 ⇒ match type_check Γ t1, type_check Γ t2 with
| Some (TArrow T11 T12),Some T2 ⇒
if beq_ty T11 T2 then Some T12 else None
| _,_ ⇒ None
end
| ttrue ⇒ Some TBool
| tfalse ⇒ Some TBool
| tif x t f ⇒ match type_check Γ x with
| Some TBool ⇒
match type_check Γ t, type_check Γ f with
| Some T1, Some T2 ⇒
if beq_ty T1 T2 then Some T1 else None
| _,_ ⇒ None
end
| _ ⇒ None
end
end.
Properties
Theorem type_checking_sound : ∀Γ t T,
type_check Γ t = Some T → has_type Γ t T.
Proof with eauto.
intros Γ t. generalize dependent Γ.
induction t; intros Γ T Htc; inversion Htc.
- (* tvar *) eauto.
- (* tapp *)
remember (type_check Γ t1) as TO1.
remember (type_check Γ 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.
destruct (beq_ty T11 T2) eqn: Heqb;
try solve by inversion.
apply beq_ty__eq in Heqb.
inversion H0; subst...
- (* tabs *)
rename i into y. rename t into T1.
remember (update Γ y T1) as G'.
remember (type_check G' t0) as TO2.
destruct TO2; try solve by inversion.
inversion H0; subst...
- (* ttrue *) eauto.
- (* tfalse *) eauto.
- (* tif *)
remember (type_check Γ t1) as TOc.
remember (type_check Γ t2) as TO1.
remember (type_check Γ 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.
destruct (beq_ty T1 T2) eqn:Heqb;
try solve by inversion.
apply beq_ty__eq in Heqb.
inversion H0. subst. subst...
Qed.
Theorem type_checking_complete : ∀Γ t T,
has_type Γ t T → type_check Γ t = Some T.
Proof with auto.
intros Γ t T Hty.
induction Hty; simpl.
- (* T_Var *) eauto.
- (* T_Abs *) rewrite IHHty...
- (* T_App *)
rewrite IHHty1. rewrite IHHty2.
rewrite (beq_ty_refl T11)...
- (* T_True *) eauto.
- (* T_False *) eauto.
- (* T_If *) rewrite IHHty1. rewrite IHHty2.
rewrite IHHty3. rewrite (beq_ty_refl T)...
Qed.
End STLCChecker.