Theory W
section "Correctness and completeness of type inference algorithm W"
theory W
imports MiniML
begin
type_synonym result_W = "(subst * typ * nat) option"
fun W :: "[expr, ctxt, nat] => result_W" where
"W (Var i) A n =
(if i < length A then Some( id_subst,
bound_typ_inst (λb. TVar(b+n)) (A!i),
n + (min_new_bound_tv (A!i)) )
else None)"
| "W (Abs e) A n = ( (S,t,m) := W e ((FVar n)#A) (Suc n);
Some( S, (S n) -> t, m) )"
| "W (App e1 e2) A n = ( (S1,t1,m1) := W e1 A n;
(S2,t2,m2) := W e2 ($S1 A) m1;
U := mgu ($S2 t1) (t2 -> (TVar m2));
Some( $U ∘ $S2 ∘ S1, U m2, Suc m2) )"
| "W (LET e1 e2) A n = ( (S1,t1,m1) := W e1 A n;
(S2,t2,m2) := W e2 ((gen ($S1 A) t1)#($S1 A)) m1;
Some( $S2 ∘ S1, t2, m2) )"
declare Suc_le_lessD [simp]
inductive_simps has_type_simps:
"A ⊢ Var n :: t"
"A ⊢ Abs e :: t"
"A ⊢ App e1 e2 ::t"
"A ⊢ LET e1 e2 ::t"
lemma W_var_ge:
"W e A n = Some (S,t,m) ⟹ n ≤ m"
proof (induction e arbitrary: A n S t m)
case Var thus ?case by (auto split: if_splits)
next
case Abs thus ?case by (fastforce split: split_option_bind_asm)
next
case App thus ?case by (fastforce split: split_option_bind_asm)
next
case LET thus ?case by (fastforce split: split_option_bind_asm)
qed
declare W_var_ge [simp]
lemma W_var_geD:
"Some (S,t,m) = W e A n ⟹ n≤m"
by (metis W_var_ge)
lemma new_tv_compatible_W:
"new_tv n A ⟹ Some (S,t,m) = W e A n ⟹ new_tv m A"
by (metis W_var_ge new_tv_le)
lemma new_tv_bound_typ_inst_sch:
"new_tv n sch ⟹ new_tv (n + (min_new_bound_tv sch)) (bound_typ_inst (λb. TVar (b + n)) sch)"
proof (induction sch)
case FVar thus ?case by simp
next
case BVar thus ?case by simp
next
case SFun thus ?case by(auto simp add: max_def nle_le dest: new_tv_le add_left_mono)
qed
lemma new_tv_W [rule_format]:
"∀n A S t m. new_tv n A ⟶ W e A n = Some (S,t,m) ⟶
new_tv m S ∧ new_tv m t"
proof (induction e)
case Var thus ?case
by (auto simp add: new_tv_bound_typ_inst_sch dest: new_tv_nth_nat_A)
next
case Abs thus ?case
apply (simp add: new_tv_subst split: split_option_bind)
by (metis lessI new_tv_Cons new_tv_FVar new_tv_Suc new_tv_compatible_W )
next
case App thus ?case
apply (simp split: split_option_bind)
by (smt (verit, ccfv_threshold) W_var_geD fun.map_comp lessI mgu_new new_tv_Fun new_tv_Suc new_tv_le new_tv_subst new_tv_subst_comp_1 new_tv_subst_scheme_list new_tv_subst_te)
next
case LET thus ?case
apply (simp split: split_option_bind)
by (metis W_var_ge new_tv_Cons new_tv_compatible_gen new_tv_le new_tv_subst_comp_1 new_tv_subst_scheme_list)
qed
lemma free_tv_bound_typ_inst1:
"v ∉ free_tv sch ⟹ v ∈ free_tv (bound_typ_inst (TVar ∘ S) sch) ⟹ ∃x. v = S x"
by (induction sch) auto
lemma free_tv_W:
"W e A n = Some (S,t,m) ⟹
(v∈free_tv S ∨ v∈free_tv t) ⟹ v<n ⟹ v∈free_tv A"
proof (induction e arbitrary: n A S t m v)
case (Var i)
show ?case
proof (cases "v ∈ free_tv (A!i)")
case True
with Var show ?thesis
by (metis W.simps(1) free_tv_nth_A_impl_free_tv_A not_None_eq)
next
case False
with Var show ?thesis
by (force simp: o_def free_tv_nth_A_impl_free_tv_A dest: free_tv_bound_typ_inst1
split: if_split_asm)
qed
next
case (Abs e n A S t m v)
then obtain S1 t1 n1 where "W e (FVar n # A) (Suc n) = Some (S1, t1, n1)"
by (metis (lifting) W.simps(2) not_None_eq option_bind_eq_None prod_cases3)
then show ?case
using Abs.IH [of "FVar n # A" "Suc n" S1 t1 n1 v] Abs.prems
by (force simp: codD cod_app_subst)
next
case (App e1 e2 n A S t m v)
then show ?case
proof (clarsimp split: split_option_bind_asm prod.split_asm)
fix S' t' n1 S1 t1 n2 S2
assume v: "v ∈ free_tv ($ S2 ∘ $ S1 ∘ S') ∨ v ∈ free_tv (S2 n2)"
and "v < n"
and e1: "W e1 A n = Some (S', t', n1)"
and e2: "W e2 ($ S' A) n1 = Some (S1, t1, n2)"
and mgu: "mgu ($ S1 t') (t1 -> TVar n2) = Some S2"
have n: "n ≤ n1" "n1 ≤ n2"
using e1 e2 by auto
show "v ∈ free_tv A"
using v
proof
assume v1: "v ∈ free_tv ($ S2 ∘ $ S1 ∘ S')"
then have "v ∈ free_tv S2 ∪ free_tv (λx. $ S1 (S' x))"
by (metis (no_types, lifting) ext comp_apply free_tv_o_subst fun.map_comp
subsetD)
moreover
have "free_tv S2 ⊆ insert n2 (free_tv ($ S1 t') ∪ free_tv t1)"
using mgu mgu_free by fastforce
ultimately
show "v ∈ free_tv A"
using App.IH n v1 ‹v<n› e1 e2 codD free_tv_app_subst_scheme_list
by (smt (verit, ccfv_threshold) Un_iff free_tv_app_subst_te free_tv_o_subst
fun.map_comp insert_iff linorder_not_less order.strict_trans2 subsetD)
next
assume v2: "v ∈ free_tv (S2 n2)"
then have "v < n1"
using App.prems n by linarith
then have "free_tv S2 ⊆ free_tv ($ S1 t') ∪ free_tv (t1 -> TVar n2)"
using mgu mgu_free by blast
then show "v ∈ free_tv A"
using App.IH n v2 ‹v<n› ‹v<n1› e1 e2 codD free_tv_app_subst_scheme_list
by (smt (verit, ccfv_threshold) UnE cod_app_subst empty_iff
free_tv_app_subst_te free_tv_typ.simps insert_iff linorder_not_less subsetD)
qed
qed
next
case (LET e1 e2 n A S t2 n3 v)
then show ?case
proof (clarsimp split: split_option_bind_asm prod.split_asm)
fix S1 t1 n2 S2
assume "v ∈ free_tv ($ S2 ∘ S1) ∨ v ∈ free_tv t2"
and "v < n"
and "W e1 A n = Some (S1, t1, n2)"
and "W e2 (gen ($ S1 A) t1 # $ S1 A) n2 = Some (S2, t2, n3)"
with LET.IH
show "v ∈ free_tv A"
by (smt (verit) Un_iff W_var_geD codD free_tv_app_subst_scheme_list
free_tv_gen_cons free_tv_o_subst order.strict_trans2 subsetD)
qed
qed
lemma weaken_A_Int_B_eq_empty: "(∀x. x ∈ A ⟶ x ∉ B) ⟹ A ∩ B = {}"
by blast
lemma weaken_not_elem_A_minus_B: "x ∉ A ∨ x ∈ B ⟹ x ∉ A - B"
by blast
lemma W_correct_lemma: "⟦new_tv n A; Some (S,t,m) = W e A n⟧ ⟹ $S A ⊢ e :: t"
proof (induction "e" arbitrary: A S t m n)
case Var thus ?case
using is_bound_typ_instance by (auto split: if_splits)
next
case (Abs e) thus ?case
apply (simp split: split_option_bind_asm prod.splits)
by (metis AbsI app_subst_Cons app_subst_type_scheme.simps(1) lessI new_tv_Cons
new_tv_FVar new_tv_Suc)
next
case (App e1 e2)
then show ?case
proof (simp split: split_option_bind_asm prod.splits)
fix S1 t1 n1 S2 t2 n2 S3
assume e1: "W e1 A n = Some (S1, t1, n1)"
and e2: "W e2 ($ S1 A) n1 = Some (S2, t2, n2)"
and mgu: "mgu ($ S2 t1) (t2 -> TVar n2) = Some S3"
show "$ (λa. $ S3 ($ S2 (S1 a))) A ⊢ App e1 e2 :: S3 n2"
proof (rule has_type.AppI)
have "$ S3 (t2 -> TVar n2) = $ S3 ($ S2 t1)"
using mgu mgu_eq by presburger
with App show "$ (λa. $ S3 ($ S2 (S1 a))) A ⊢ e1 :: $ S3 t2 -> S3 n2"
by (metis (no_types) Type.app_subst_Fun Type.app_subst_TVar e1 has_type_cl_sub subst_comp_scheme_list)
show "$ (λa. $ S3 ($ S2 (S1 a))) A ⊢ e2 :: $ S3 t2"
using e1 e2 mgu App
by (metis has_type_cl_sub new_tv_W new_tv_compatible_W new_tv_subst_scheme_list
subst_comp_scheme_list)
qed
qed
next
case (LET e1 e2) thus ?case
proof (simp split: split_option_bind_asm prod.splits)
fix S1 t1 m1 S2
assume "new_tv n A"
and e1: "W e1 A n = Some (S1, t1, m1)"
and e2: "W e2 (gen ($ S1 A) t1 # $ S1 A) m1 = Some (S2, t, m)"
show "$ (λa. $ S2 (S1 a)) A ⊢ LET e1 e2 :: t"
proof (rule has_type.LETI)
show "$ (λa. $ S2 (S1 a)) A ⊢ e1 :: $ S2 t1"
using LET e1 by (metis (no_types, lifting) has_type_cl_sub subst_comp_scheme_list)
have "free_tv S2 ∩ (free_tv t1 - free_tv ($ S1 A)) = {}"
using e1 e2 LET
by (smt (verit) DiffD2 Diff_subset free_tv_W free_tv_gen_cons
free_tv_le_new_tv new_tv_W subsetD weaken_A_Int_B_eq_empty)
then
show "gen ($ (λa. $ S2 (S1 a)) A) ($ S2 t1) # $ (λa. $ S2 (S1 a)) A ⊢ e2 :: t"
using e1 e2 LET
by (metis app_subst_Cons gen_subst_commutes new_tv_Cons new_tv_W new_tv_compatible_W
new_tv_compatible_gen new_tv_subst_scheme_list subst_comp_scheme_list)
qed
qed
qed
lemma W_complete_lemma:
"⟦$S' A ⊢ e :: t'; new_tv n A⟧ ⟹
∃S t. (∃m. W e A n = Some (S,t,m)) ∧ (∃R. $S' A = $R ($S A) ∧ t' = $R t)"
proof (induction e arbitrary: S' A t' n)
case (Var u) thus ?case
proof (clarsimp simp add: has_type_simps is_bound_typ_instance)
fix S :: "nat ⇒ typ"
assume A: "new_tv n A" "u < length A"
show "∃R. $ S' A = $ R A ∧
bound_typ_inst S ($ S' A ! u) = $ R (bound_typ_inst (λb. TVar (b + n)) (A ! u))"
proof (intro exI conjI)
show "$ S' A = $ (λx. if x < n then S' x else S (x - n)) A"
using Var.prems(2) new_if_subst_type_scheme_list by force
show "bound_typ_inst S ($ S' A ! u) = $ (λx. if x < n then S' x else S (x - n)) (bound_typ_inst (λb. TVar (b + n)) (A ! u))"
using A
by (simp add: new_if_subst_type_scheme new_tv_nth_nat_A o_def nth_subst
flip: bound_typ_inst_composed_subst)
qed
qed
next
case (Abs e S' A t' n)
then obtain t1 t2 where "t' = t1 -> t2" "mk_scheme t1 # $ S' A ⊢ e :: t2"
by (auto simp: has_type_simps)
with Abs.prems Abs.IH[of "λx. if x=n then t1 else (S' x)" "(FVar n) #A" t2 "Suc n"]
show ?case
by (force dest!: mk_scheme_injective)
next
case (App e1 e2)
then obtain t2 where e2t: "$ S' A ⊢ e2 :: t2" and e1t: "$ S' A ⊢ e1 :: t2 -> t'"
by (auto simp: has_type_simps)
then obtain S t m R
where e1: "W e1 A n = Some (S, t, m)" and R: "$ S' A = $ R ($ S A)" "t2 -> t' = $ R t"
using App by blast
with App.prems have new_tv_m: "new_tv m ($ S A)"
by (metis new_tv_W new_tv_compatible_W new_tv_subst_scheme_list)
with App R
obtain Sa ta ma Ra where We2: "W e2 ($ S A) m = Some (Sa, ta, ma)"
and RSA: "$ R ($ S A) = $ Ra ($ Sa ($ S A))"
and t2eq: "t2 = $ Ra ta"
by (metis e2t)
define F where "F ≡ (λx. if x = ma then t'
else if x ∈ free_tv t - free_tv Sa then R x
else Ra x)"
have "ma ∉ free_tv t"
by (metis App.prems(2) W_var_geD We2 e1 new_tv_W new_tv_le
new_tv_not_free_tv)
have "$ F (Sa na) = R na" if "na ∈ free_tv t" for na
proof -
have "na ≠ ma"
using ‹ma ∉ free_tv t› that by auto
show ?thesis
proof (cases "na ∈ free_tv Sa")
case True
then have "R na = $ Ra (Sa na)"
by (metis (lifting) App.prems(2) RSA We2 e1 eq_subst_scheme_list_eq_free free_tv_W
free_tv_le_new_tv new_tv_W subst_comp_scheme_list that)
then show ?thesis
by (metis F_def True We2 new_tv_m codD cod_app_subst eq_free_eq_subst_te
new_tv_W new_tv_not_free_tv weaken_not_elem_A_minus_B)
next
case False
then show ?thesis
using not_free_impl_id [OF False] ‹na ≠ ma› that
by (simp add: F_def)
qed
qed
then have *: "$ F ($ Sa t) = $ Ra ta -> t'"
using eq_free_eq_subst_te subst_comp_te using R t2eq by fastforce
moreover have "Ra na = F na"
if "na ∈ free_tv ta" for na
proof -
have "na ≠ ma"
using We2 new_tv_W new_tv_m new_tv_not_free_tv that by blast
show ?thesis
proof (cases "na ∈ free_tv t - free_tv Sa")
case True
then have "$ R ($ S A) = $ (λx. $ Ra (Sa x)) ($ S A)"
by (metis RSA subst_comp_scheme_list)
then have "Ra na = R na"
by (metis that App.prems(2) DiffE True Type.app_subst_TVar We2 free_tv_W e1
eq_subst_scheme_list_eq_free free_tv_le_new_tv new_tv_W not_free_impl_id)
with ‹na ≠ ma› True show ?thesis
by (simp add: F_def)
next
case False
then show ?thesis
using F_def ‹na ≠ ma› by presburger
qed
qed
ultimately have "$ F ($ Sa t) = $ F (ta -> (TVar ma))"
by (metis eq_free_eq_subst_te F_def Type.app_subst_Fun Type.app_subst_TVar)
with mgu_Some obtain Sx Rb where Sx: "mgu ($ Sa t) (ta -> TVar ma) = Some Sx"
and Rb: "F = $ Rb ∘ Sx"
using mgu_mg by blast
have t': "t' = $ Rb (Sx ma)"
by (metis F_def Rb comp_def)
have "$ Ra ($ Sa ($ S A)) = $ (λx. $ Rb (Sx x)) ($ Sa ($ S A))"
proof (intro eq_free_eq_subst_scheme_list)
fix na :: nat
assume na: "na ∈ free_tv ($ Sa ($ S A))"
then have "ma ≠ na"
by (metis We2 new_tv_W new_tv_compatible_W new_tv_m new_tv_not_free_tv
new_tv_subst_scheme_list)
show "Ra na = $ Rb (Sx na)"
proof (cases "na ∈ free_tv t - free_tv Sa")
case True
then have "na ∈ cod Sa ∪ free_tv ($ S A)"
using free_tv_app_subst_scheme_list na by blast
with ‹ma ≠ na› Rb show ?thesis
by (smt (verit, ccfv_SIG) DiffD2 F_def RSA Rb Type.app_subst_TVar Un_iff codD
comp_apply eq_subst_scheme_list_eq_free not_free_impl_id subst_comp_scheme_list)
next
case False
then show ?thesis
by (metis F_def Rb ‹ma ≠ na› comp_apply)
qed
qed
then have "$ S' A = $ Rb ($ ($ Sx ∘ $ Sa ∘ S) A)"
by (metis (no_types, lifting) ext R(1) RSA comp_apply fun.map_comp
subst_comp_scheme_list)
with We2 Sx show ?case
by (auto simp add: e1 t')
next
case (LET e1 e2)
then obtain t1 where t1: "$ S' A ⊢ e1 :: t1" "gen ($ S' A) t1 # $ S' A ⊢ e2 :: t'"
by (auto simp: has_type_simps)
then obtain S t m R where e1: "W e1 A n = Some (S, t, m)" "$ S' A = $ R ($ S A)"
and "gen ($ R ($ S A)) ($ R t) # $ R ($ S A) ⊢ e2 :: t'"
using LET by metis
then have "$ R (gen ($ S A) t) # $ R ($ S A) ⊢ e2 :: t'"
using gen_bound_typ_instance has_type_le_env le_env_Cons le_env_refl
by presburger
moreover
have "new_tv m (gen ($ S A) t) ∧ new_tv m ($ S A)"
using LET.prems e1
by (metis new_tv_W new_tv_compatible_W new_tv_compatible_gen new_tv_subst_scheme_list)
ultimately show ?case
using LET.IH(2)[of R "gen ($ S A) t # $ S A" t' m] e1 subst_comp_scheme_list
by auto
qed
theorem W_complete:
"[] ⊢ e :: t' ⟹ ∃S t m. W e [] n = Some(S,t,m) ∧ (∃R. t' = $ R t)"
by (metis W_complete_lemma app_subst_Nil new_tv_Nil)
end