diff --git a/src/HOL/Nominal/Examples/Crary.thy b/src/HOL/Nominal/Examples/Crary.thy --- a/src/HOL/Nominal/Examples/Crary.thy +++ b/src/HOL/Nominal/Examples/Crary.thy @@ -1,964 +1,935 @@ (* *) (* Formalisation of the chapter on Logical Relations *) (* and a Case Study in Equivalence Checking *) (* by Karl Crary from the book on Advanced Topics in *) (* Types and Programming Languages, MIT Press 2005 *) (* The formalisation was done by Julien Narboux and *) (* Christian Urban. *) theory Crary imports "HOL-Nominal.Nominal" begin atom_decl name nominal_datatype ty = TBase | TUnit | Arrow "ty" "ty" ("_\_" [100,100] 100) nominal_datatype trm = Unit | Var "name" ("Var _" [100] 100) | Lam "\name\trm" ("Lam [_]._" [100,100] 100) | App "trm" "trm" ("App _ _" [110,110] 100) | Const "nat" type_synonym Ctxt = "(name\ty) list" type_synonym Subst = "(name\trm) list" lemma perm_ty[simp]: fixes T::"ty" and pi::"name prm" shows "pi\T = T" by (induct T rule: ty.induct) (simp_all) lemma fresh_ty[simp]: fixes x::"name" and T::"ty" shows "x\T" by (simp add: fresh_def supp_def) lemma ty_cases: fixes T::ty shows "(\ T\<^sub>1 T\<^sub>2. T=T\<^sub>1\T\<^sub>2) \ T=TUnit \ T=TBase" by (induct T rule:ty.induct) (auto) instantiation ty :: size begin nominal_primrec size_ty where "size (TBase) = 1" | "size (TUnit) = 1" | "size (T\<^sub>1\T\<^sub>2) = size T\<^sub>1 + size T\<^sub>2" by (rule TrueI)+ instance .. end lemma ty_size_greater_zero[simp]: fixes T::"ty" shows "size T > 0" by (nominal_induct rule: ty.strong_induct) (simp_all) section \Substitutions\ fun lookup :: "Subst \ name \ trm" where "lookup [] x = Var x" | "lookup ((y,T)#\) x = (if x=y then T else lookup \ x)" lemma lookup_eqvt[eqvt]: fixes pi::"name prm" shows "pi\(lookup \ x) = lookup (pi\\) (pi\x)" -by (induct \) (auto simp add: perm_bij) +by (induct \) (auto simp: perm_bij) lemma lookup_fresh: fixes z::"name" assumes a: "z\\" "z\x" shows "z\ lookup \ x" using a by (induct rule: lookup.induct) - (auto simp add: fresh_list_cons) + (auto simp: fresh_list_cons) lemma lookup_fresh': assumes a: "z\\" shows "lookup \ z = Var z" using a by (induct rule: lookup.induct) - (auto simp add: fresh_list_cons fresh_prod fresh_atm) + (auto simp: fresh_list_cons fresh_prod fresh_atm) nominal_primrec psubst :: "Subst \ trm \ trm" ("_<_>" [100,100] 130) where "\<(Var x)> = (lookup \ x)" | "\<(App t\<^sub>1 t\<^sub>2)> = App \1> \2>" | "x\\ \ \<(Lam [x].t)> = Lam [x].(\)" | "\<(Const n)> = Const n" | "\<(Unit)> = Unit" -apply(finite_guess)+ -apply(rule TrueI)+ -apply(simp add: abs_fresh)+ -apply(fresh_guess)+ -done + by(finite_guess | simp add: abs_fresh | fresh_guess)+ abbreviation subst :: "trm \ name \ trm \ trm" ("_[_::=_]" [100,100,100] 100) where "t[x::=t'] \ ([(x,t')])" lemma subst[simp]: shows "(Var x)[y::=t'] = (if x=y then t' else (Var x))" and "(App t\<^sub>1 t\<^sub>2)[y::=t'] = App (t\<^sub>1[y::=t']) (t\<^sub>2[y::=t'])" and "x\(y,t') \ (Lam [x].t)[y::=t'] = Lam [x].(t[y::=t'])" and "Const n[y::=t'] = Const n" and "Unit [y::=t'] = Unit" by (simp_all add: fresh_list_cons fresh_list_nil) lemma subst_eqvt[eqvt]: fixes pi::"name prm" shows "pi\(t[x::=t']) = (pi\t)[(pi\x)::=(pi\t')]" by (nominal_induct t avoiding: x t' rule: trm.strong_induct) (perm_simp add: fresh_bij)+ lemma subst_rename: fixes c::"name" assumes a: "c\t\<^sub>1" shows "t\<^sub>1[a::=t\<^sub>2] = ([(c,a)]\t\<^sub>1)[c::=t\<^sub>2]" using a -apply(nominal_induct t\<^sub>1 avoiding: a c t\<^sub>2 rule: trm.strong_induct) -apply(simp add: trm.inject calc_atm fresh_atm abs_fresh perm_nat_def)+ -done + by (nominal_induct t\<^sub>1 avoiding: a c t\<^sub>2 rule: trm.strong_induct) + (auto simp: trm.inject calc_atm fresh_atm abs_fresh perm_nat_def) lemma fresh_psubst: fixes z::"name" assumes a: "z\t" "z\\" shows "z\(\)" using a by (nominal_induct t avoiding: z \ t rule: trm.strong_induct) - (auto simp add: abs_fresh lookup_fresh) + (auto simp: abs_fresh lookup_fresh) lemma fresh_subst'': fixes z::"name" assumes "z\t\<^sub>2" shows "z\t\<^sub>1[z::=t\<^sub>2]" using assms by (nominal_induct t\<^sub>1 avoiding: t\<^sub>2 z rule: trm.strong_induct) - (auto simp add: abs_fresh fresh_nat fresh_atm) + (auto simp: abs_fresh fresh_nat fresh_atm) lemma fresh_subst': fixes z::"name" assumes "z\[y].t\<^sub>1" "z\t\<^sub>2" shows "z\t\<^sub>1[y::=t\<^sub>2]" using assms by (nominal_induct t\<^sub>1 avoiding: y t\<^sub>2 z rule: trm.strong_induct) - (auto simp add: abs_fresh fresh_nat fresh_atm) + (auto simp: abs_fresh fresh_nat fresh_atm) lemma fresh_subst: fixes z::"name" assumes a: "z\t\<^sub>1" "z\t\<^sub>2" shows "z\t\<^sub>1[y::=t\<^sub>2]" using a -by (auto simp add: fresh_subst' abs_fresh) +by (auto simp: fresh_subst' abs_fresh) lemma fresh_psubst_simp: assumes "x\t" shows "((x,u)#\) = \" using assms proof (nominal_induct t avoiding: x u \ rule: trm.strong_induct) case (Lam y t x u) have fs: "y\\" "y\x" "y\u" by fact+ moreover have "x\ Lam [y].t" by fact ultimately have "x\t" by (simp add: abs_fresh fresh_atm) moreover have ih:"\n T. n\t \ ((n,T)#\) = \" by fact ultimately have "((x,u)#\) = \" by auto moreover have "((x,u)#\) = Lam [y].(((x,u)#\))" using fs by (simp add: fresh_list_cons fresh_prod) moreover have " \ = Lam [y]. (\)" using fs by simp ultimately show "((x,u)#\) = \" by auto -qed (auto simp add: fresh_atm abs_fresh) +qed (auto simp: fresh_atm abs_fresh) lemma forget: fixes x::"name" assumes a: "x\t" shows "t[x::=t'] = t" using a by (nominal_induct t avoiding: x t' rule: trm.strong_induct) - (auto simp add: fresh_atm abs_fresh) + (auto simp: fresh_atm abs_fresh) lemma subst_fun_eq: fixes u::trm assumes h:"[x].t\<^sub>1 = [y].t\<^sub>2" shows "t\<^sub>1[x::=u] = t\<^sub>2[y::=u]" proof - { assume "x=y" and "t\<^sub>1=t\<^sub>2" then have ?thesis using h by simp } moreover { assume h1:"x \ y" and h2:"t\<^sub>1=[(x,y)] \ t\<^sub>2" and h3:"x \ t\<^sub>2" then have "([(x,y)] \ t\<^sub>2)[x::=u] = t\<^sub>2[y::=u]" by (simp add: subst_rename) then have ?thesis using h2 by simp } ultimately show ?thesis using alpha h by blast qed lemma psubst_empty[simp]: shows "[] = t" by (nominal_induct t rule: trm.strong_induct) - (auto simp add: fresh_list_nil) + (auto simp: fresh_list_nil) lemma psubst_subst_psubst: assumes h:"c\\" shows "\[c::=s] = ((c,s)#\)" using h by (nominal_induct t avoiding: \ c s rule: trm.strong_induct) - (auto simp add: fresh_list_cons fresh_atm forget lookup_fresh lookup_fresh' fresh_psubst) + (auto simp: fresh_list_cons fresh_atm forget lookup_fresh lookup_fresh' fresh_psubst) lemma subst_fresh_simp: assumes a: "x\\" shows "\ = Var x" using a -by (induct \ arbitrary: x) (auto simp add:fresh_list_cons fresh_prod fresh_atm) +by (induct \ arbitrary: x) (auto simp:fresh_list_cons fresh_prod fresh_atm) lemma psubst_subst_propagate: assumes "x\\" shows "\ = \[x::=\]" using assms proof (nominal_induct t avoiding: x u \ rule: trm.strong_induct) case (Var n x u \) { assume "x=n" moreover have "x\\" by fact ultimately have "\ = \[x::=\]" using subst_fresh_simp by auto } moreover { assume h:"x\n" - then have "x\Var n" by (auto simp add: fresh_atm) + then have "x\Var n" by (auto simp: fresh_atm) moreover have "x\\" by fact ultimately have "x\\" using fresh_psubst by blast then have " \[x::=\] = \" using forget by auto then have "\ = \[x::=\]" using h by auto } ultimately show ?case by auto next case (Lam n t x u \) have fs:"n\x" "n\u" "n\\" "x\\" by fact+ have ih:"\ y s \. y\\ \ ((\<(t[y::=s])>) = ((\)[y::=(\)]))" by fact have "\ <(Lam [n].t)[x::=u]> = \" using fs by auto then have "\ <(Lam [n].t)[x::=u]> = Lam [n]. \" using fs by auto moreover have "\ = \[x::=\]" using ih fs by blast ultimately have "\ <(Lam [n].t)[x::=u]> = Lam [n].(\[x::=\])" by auto moreover have "Lam [n].(\[x::=\]) = (Lam [n].\)[x::=\]" using fs fresh_psubst by auto ultimately have "\<(Lam [n].t)[x::=u]> = (Lam [n].\)[x::=\]" using fs by auto then show "\<(Lam [n].t)[x::=u]> = \[x::=\]" using fs by auto qed (auto) section \Typing\ inductive valid :: "Ctxt \ bool" where v_nil[intro]: "valid []" | v_cons[intro]: "\valid \;a\\\ \ valid ((a,T)#\)" equivariance valid inductive_cases valid_cons_elim_auto[elim]:"valid ((x,T)#\)" abbreviation "sub_context" :: "Ctxt \ Ctxt \ bool" (" _ \ _ " [55,55] 55) where "\\<^sub>1 \ \\<^sub>2 \ \a T. (a,T)\set \\<^sub>1 \ (a,T)\set \\<^sub>2" lemma valid_monotonicity[elim]: fixes \ \' :: Ctxt assumes a: "\ \ \'" and b: "x\\'" shows "(x,T\<^sub>1)#\ \ (x,T\<^sub>1)#\'" using a b by auto lemma fresh_context: fixes \ :: "Ctxt" and a :: "name" assumes "a\\" shows "\(\\::ty. (a,\)\set \)" using assms by (induct \) - (auto simp add: fresh_prod fresh_list_cons fresh_atm) + (auto simp: fresh_prod fresh_list_cons fresh_atm) lemma type_unicity_in_context: assumes a: "valid \" and b: "(x,T\<^sub>1) \ set \" and c: "(x,T\<^sub>2) \ set \" shows "T\<^sub>1=T\<^sub>2" using a b c by (induct \) (auto dest!: fresh_context) inductive typing :: "Ctxt\trm\ty\bool" (" _ \ _ : _ " [60,60,60] 60) where T_Var[intro]: "\valid \; (x,T)\set \\ \ \ \ Var x : T" | T_App[intro]: "\\ \ e\<^sub>1 : T\<^sub>1\T\<^sub>2; \ \ e\<^sub>2 : T\<^sub>1\ \ \ \ App e\<^sub>1 e\<^sub>2 : T\<^sub>2" | T_Lam[intro]: "\x\\; (x,T\<^sub>1)#\ \ t : T\<^sub>2\ \ \ \ Lam [x].t : T\<^sub>1\T\<^sub>2" | T_Const[intro]: "valid \ \ \ \ Const n : TBase" | T_Unit[intro]: "valid \ \ \ \ Unit : TUnit" equivariance typing nominal_inductive typing by (simp_all add: abs_fresh) lemma typing_implies_valid: assumes a: "\ \ t : T" shows "valid \" using a by (induct) (auto) declare trm.inject [simp add] declare ty.inject [simp add] inductive_cases typing_inv_auto[elim]: "\ \ Lam [x].t : T" "\ \ Var x : T" "\ \ App x y : T" "\ \ Const n : T" "\ \ Unit : TUnit" "\ \ s : TUnit" declare trm.inject [simp del] declare ty.inject [simp del] section \Definitional Equivalence\ inductive def_equiv :: "Ctxt\trm\trm\ty\bool" ("_ \ _ \ _ : _" [60,60] 60) where Q_Refl[intro]: "\ \ t : T \ \ \ t \ t : T" | Q_Symm[intro]: "\ \ t \ s : T \ \ \ s \ t : T" | Q_Trans[intro]: "\\ \ s \ t : T; \ \ t \ u : T\ \ \ \ s \ u : T" | Q_Abs[intro]: "\x\\; (x,T\<^sub>1)#\ \ s\<^sub>2 \ t\<^sub>2 : T\<^sub>2\ \ \ \ Lam [x]. s\<^sub>2 \ Lam [x]. t\<^sub>2 : T\<^sub>1 \ T\<^sub>2" | Q_App[intro]: "\\ \ s\<^sub>1 \ t\<^sub>1 : T\<^sub>1 \ T\<^sub>2 ; \ \ s\<^sub>2 \ t\<^sub>2 : T\<^sub>1\ \ \ \ App s\<^sub>1 s\<^sub>2 \ App t\<^sub>1 t\<^sub>2 : T\<^sub>2" | Q_Beta[intro]: "\x\(\,s\<^sub>2,t\<^sub>2); (x,T\<^sub>1)#\ \ s\<^sub>1 \ t\<^sub>1 : T\<^sub>2 ; \ \ s\<^sub>2 \ t\<^sub>2 : T\<^sub>1\ \ \ \ App (Lam [x]. s\<^sub>1) s\<^sub>2 \ t\<^sub>1[x::=t\<^sub>2] : T\<^sub>2" | Q_Ext[intro]: "\x\(\,s,t); (x,T\<^sub>1)#\ \ App s (Var x) \ App t (Var x) : T\<^sub>2\ \ \ \ s \ t : T\<^sub>1 \ T\<^sub>2" | Q_Unit[intro]: "\\ \ s : TUnit; \ \ t: TUnit\ \ \ \ s \ t : TUnit" equivariance def_equiv nominal_inductive def_equiv by (simp_all add: abs_fresh fresh_subst'') lemma def_equiv_implies_valid: assumes a: "\ \ t \ s : T" shows "valid \" using a by (induct) (auto elim: typing_implies_valid) section \Weak Head Reduction\ inductive whr_def :: "trm\trm\bool" ("_ \ _" [80,80] 80) where QAR_Beta[intro]: "App (Lam [x]. t\<^sub>1) t\<^sub>2 \ t\<^sub>1[x::=t\<^sub>2]" | QAR_App[intro]: "t\<^sub>1 \ t\<^sub>1' \ App t\<^sub>1 t\<^sub>2 \ App t\<^sub>1' t\<^sub>2" declare trm.inject [simp add] declare ty.inject [simp add] inductive_cases whr_inv_auto[elim]: "t \ t'" "Lam [x].t \ t'" "App (Lam [x].t12) t2 \ t" "Var x \ t" "Const n \ t" "App p q \ t" "t \ Const n" "t \ Var x" "t \ App p q" declare trm.inject [simp del] declare ty.inject [simp del] equivariance whr_def section \Weak Head Normalisation\ abbreviation nf :: "trm \ bool" ("_ \|" [100] 100) where "t\| \ \(\ u. t \ u)" inductive whn_def :: "trm\trm\bool" ("_ \ _" [80,80] 80) where QAN_Reduce[intro]: "\s \ t; t \ u\ \ s \ u" | QAN_Normal[intro]: "t\| \ t \ t" declare trm.inject[simp] inductive_cases whn_inv_auto[elim]: "t \ t'" declare trm.inject[simp del] equivariance whn_def lemma red_unicity : assumes a: "x \ a" and b: "x \ b" shows "a=b" using a b -apply (induct arbitrary: b) -apply (erule whr_inv_auto(3)) -apply (clarify) -apply (rule subst_fun_eq) -apply (simp) -apply (force) -apply (erule whr_inv_auto(6)) -apply (blast)+ -done +by (induct arbitrary: b) (use subst_fun_eq in blast)+ lemma nf_unicity : assumes "x \ a" and "x \ b" shows "a=b" using assms proof (induct arbitrary: b) case (QAN_Reduce x t a b) have h:"x \ t" "t \ a" by fact+ have ih:"\b. t \ b \ a = b" by fact - have "x \ b" by fact - then obtain t' where "x \ t'" and hl:"t' \ b" using h by auto + obtain t' where "x \ t'" and hl:"t' \ b" using h \x \ b\ by auto then have "t=t'" using h red_unicity by auto then show "a=b" using ih hl by auto qed (auto) section \Algorithmic Term Equivalence and Algorithmic Path Equivalence\ inductive alg_equiv :: "Ctxt\trm\trm\ty\bool" ("_ \ _ \ _ : _" [60,60,60,60] 60) and alg_path_equiv :: "Ctxt\trm\trm\ty\bool" ("_ \ _ \ _ : _" [60,60,60,60] 60) where QAT_Base[intro]: "\s \ p; t \ q; \ \ p \ q : TBase\ \ \ \ s \ t : TBase" | QAT_Arrow[intro]: "\x\(\,s,t); (x,T\<^sub>1)#\ \ App s (Var x) \ App t (Var x) : T\<^sub>2\ \ \ \ s \ t : T\<^sub>1 \ T\<^sub>2" | QAT_One[intro]: "valid \ \ \ \ s \ t : TUnit" | QAP_Var[intro]: "\valid \;(x,T) \ set \\ \ \ \ Var x \ Var x : T" | QAP_App[intro]: "\\ \ p \ q : T\<^sub>1 \ T\<^sub>2; \ \ s \ t : T\<^sub>1\ \ \ \ App p s \ App q t : T\<^sub>2" | QAP_Const[intro]: "valid \ \ \ \ Const n \ Const n : TBase" equivariance alg_equiv nominal_inductive alg_equiv avoids QAT_Arrow: x by simp_all declare trm.inject [simp add] declare ty.inject [simp add] inductive_cases alg_equiv_inv_auto[elim]: "\ \ s\t : TBase" "\ \ s\t : T\<^sub>1 \ T\<^sub>2" "\ \ s\t : TBase" "\ \ s\t : TUnit" "\ \ s\t : T\<^sub>1 \ T\<^sub>2" "\ \ Var x \ t : T" "\ \ Var x \ t : T'" "\ \ s \ Var x : T" "\ \ s \ Var x : T'" "\ \ Const n \ t : T" "\ \ s \ Const n : T" "\ \ App p s \ t : T" "\ \ s \ App q t : T" "\ \ Lam[x].s \ t : T" "\ \ t \ Lam[x].s : T" declare trm.inject [simp del] declare ty.inject [simp del] lemma Q_Arrow_strong_inversion: assumes fs: "x\\" "x\t" "x\u" and h: "\ \ t \ u : T\<^sub>1\T\<^sub>2" shows "(x,T\<^sub>1)#\ \ App t (Var x) \ App u (Var x) : T\<^sub>2" proof - obtain y where fs2: "y\(\,t,u)" and "(y,T\<^sub>1)#\ \ App t (Var y) \ App u (Var y) : T\<^sub>2" using h by auto then have "([(x,y)]\((y,T\<^sub>1)#\)) \ [(x,y)]\ App t (Var y) \ [(x,y)]\ App u (Var y) : T\<^sub>2" using alg_equiv.eqvt[simplified] by blast then show ?thesis using fs fs2 by (perm_simp) qed (* Warning this lemma is false: lemma algorithmic_type_unicity: shows "\ \ \ s \ t : T ; \ \ s \ u : T' \ \ T = T'" and "\ \ \ s \ t : T ; \ \ s \ u : T' \ \ T = T'" Here is the counter example : \ \ Const n \ Const n : Tbase and \ \ Const n \ Const n : TUnit *) lemma algorithmic_path_type_unicity: shows "\ \ s \ t : T \ \ \ s \ u : T' \ T = T'" proof (induct arbitrary: u T' rule: alg_equiv_alg_path_equiv.inducts(2) [of _ _ _ _ _ "%a b c d . True" ]) case (QAP_Var \ x T u T') have "\ \ Var x \ u : T'" by fact then have "u=Var x" and "(x,T') \ set \" by auto moreover have "valid \" "(x,T) \ set \" by fact+ ultimately show "T=T'" using type_unicity_in_context by auto next case (QAP_App \ p q T\<^sub>1 T\<^sub>2 s t u T\<^sub>2') have ih:"\u T. \ \ p \ u : T \ T\<^sub>1\T\<^sub>2 = T" by fact have "\ \ App p s \ u : T\<^sub>2'" by fact then obtain r t T\<^sub>1' where "u = App r t" "\ \ p \ r : T\<^sub>1' \ T\<^sub>2'" by auto with ih have "T\<^sub>1\T\<^sub>2 = T\<^sub>1' \ T\<^sub>2'" by auto then show "T\<^sub>2=T\<^sub>2'" using ty.inject by auto qed (auto) lemma alg_path_equiv_implies_valid: shows "\ \ s \ t : T \ valid \" and "\ \ s \ t : T \ valid \" by (induct rule : alg_equiv_alg_path_equiv.inducts) auto lemma algorithmic_symmetry: shows "\ \ s \ t : T \ \ \ t \ s : T" and "\ \ s \ t : T \ \ \ t \ s : T" by (induct rule: alg_equiv_alg_path_equiv.inducts) - (auto simp add: fresh_prod) + (auto simp: fresh_prod) lemma algorithmic_transitivity: shows "\ \ s \ t : T \ \ \ t \ u : T \ \ \ s \ u : T" and "\ \ s \ t : T \ \ \ t \ u : T \ \ \ s \ u : T" proof (nominal_induct \ s t T and \ s t T avoiding: u rule: alg_equiv_alg_path_equiv.strong_inducts) case (QAT_Base s p t q \ u) have "\ \ t \ u : TBase" by fact then obtain r' q' where b1: "t \ q'" and b2: "u \ r'" and b3: "\ \ q' \ r' : TBase" by auto have ih: "\ \ q \ r' : TBase \ \ \ p \ r' : TBase" by fact have "t \ q" by fact with b1 have eq: "q=q'" by (simp add: nf_unicity) with ih b3 have "\ \ p \ r' : TBase" by simp moreover have "s \ p" by fact ultimately show "\ \ s \ u : TBase" using b2 by auto next case (QAT_Arrow x \ s t T\<^sub>1 T\<^sub>2 u) have ih:"(x,T\<^sub>1)#\ \ App t (Var x) \ App u (Var x) : T\<^sub>2 \ (x,T\<^sub>1)#\ \ App s (Var x) \ App u (Var x) : T\<^sub>2" by fact have fs: "x\\" "x\s" "x\t" "x\u" by fact+ have "\ \ t \ u : T\<^sub>1\T\<^sub>2" by fact then have "(x,T\<^sub>1)#\ \ App t (Var x) \ App u (Var x) : T\<^sub>2" using fs by (simp add: Q_Arrow_strong_inversion) with ih have "(x,T\<^sub>1)#\ \ App s (Var x) \ App u (Var x) : T\<^sub>2" by simp - then show "\ \ s \ u : T\<^sub>1\T\<^sub>2" using fs by (auto simp add: fresh_prod) + then show "\ \ s \ u : T\<^sub>1\T\<^sub>2" using fs by (auto simp: fresh_prod) next case (QAP_App \ p q T\<^sub>1 T\<^sub>2 s t u) have "\ \ App q t \ u : T\<^sub>2" by fact then obtain r T\<^sub>1' v where ha: "\ \ q \ r : T\<^sub>1'\T\<^sub>2" and hb: "\ \ t \ v : T\<^sub>1'" and eq: "u = App r v" by auto have ih1: "\ \ q \ r : T\<^sub>1\T\<^sub>2 \ \ \ p \ r : T\<^sub>1\T\<^sub>2" by fact have ih2:"\ \ t \ v : T\<^sub>1 \ \ \ s \ v : T\<^sub>1" by fact have "\ \ p \ q : T\<^sub>1\T\<^sub>2" by fact then have "\ \ q \ p : T\<^sub>1\T\<^sub>2" by (simp add: algorithmic_symmetry) with ha have "T\<^sub>1'\T\<^sub>2 = T\<^sub>1\T\<^sub>2" using algorithmic_path_type_unicity by simp then have "T\<^sub>1' = T\<^sub>1" by (simp add: ty.inject) then have "\ \ s \ v : T\<^sub>1" "\ \ p \ r : T\<^sub>1\T\<^sub>2" using ih1 ih2 ha hb by auto then show "\ \ App p s \ u : T\<^sub>2" using eq by auto qed (auto) lemma algorithmic_weak_head_closure: shows "\ \ s \ t : T \ s' \ s \ t' \ t \ \ \ s' \ t' : T" -apply (nominal_induct \ s t T avoiding: s' t' - rule: alg_equiv_alg_path_equiv.strong_inducts(1) [of _ _ _ _ "%a b c d e. True"]) -apply(auto intro!: QAT_Arrow) -done +proof (nominal_induct \ s t T avoiding: s' t' + rule: alg_equiv_alg_path_equiv.strong_inducts(1) [of _ _ _ _ "\a b c d e. True"]) +qed(auto intro!: QAT_Arrow) lemma algorithmic_monotonicity: shows "\ \ s \ t : T \ \ \ \' \ valid \' \ \' \ s \ t : T" and "\ \ s \ t : T \ \ \ \' \ valid \' \ \' \ s \ t : T" proof (nominal_induct \ s t T and \ s t T avoiding: \' rule: alg_equiv_alg_path_equiv.strong_inducts) case (QAT_Arrow x \ s t T\<^sub>1 T\<^sub>2 \') have fs:"x\\" "x\s" "x\t" "x\\'" by fact+ have h2:"\ \ \'" by fact have ih:"\\'. \(x,T\<^sub>1)#\ \ \'; valid \'\ \ \' \ App s (Var x) \ App t (Var x) : T\<^sub>2" by fact have "valid \'" by fact then have "valid ((x,T\<^sub>1)#\')" using fs by auto moreover have sub: "(x,T\<^sub>1)#\ \ (x,T\<^sub>1)#\'" using h2 by auto ultimately have "(x,T\<^sub>1)#\' \ App s (Var x) \ App t (Var x) : T\<^sub>2" using ih by simp - then show "\' \ s \ t : T\<^sub>1\T\<^sub>2" using fs by (auto simp add: fresh_prod) + then show "\' \ s \ t : T\<^sub>1\T\<^sub>2" using fs by (auto simp: fresh_prod) qed (auto) lemma path_equiv_implies_nf: assumes "\ \ s \ t : T" shows "s \|" and "t \|" using assms by (induct rule: alg_equiv_alg_path_equiv.inducts(2)) (simp, auto) section \Logical Equivalence\ function log_equiv :: "(Ctxt \ trm \ trm \ ty \ bool)" ("_ \ _ is _ : _" [60,60,60,60] 60) where "\ \ s is t : TUnit = True" | "\ \ s is t : TBase = \ \ s \ t : TBase" | "\ \ s is t : (T\<^sub>1 \ T\<^sub>2) = (\\' s' t'. \\\' \ valid \' \ \' \ s' is t' : T\<^sub>1 \ (\' \ (App s s') is (App t t') : T\<^sub>2))" -apply (auto simp add: ty.inject) -apply (subgoal_tac "(\T\<^sub>1 T\<^sub>2. b=T\<^sub>1 \ T\<^sub>2) \ b=TUnit \ b=TBase" ) -apply (force) -apply (rule ty_cases) -done +using ty_cases by (force simp: ty.inject)+ termination by lexicographic_order lemma logical_monotonicity: fixes \ \' :: Ctxt assumes a1: "\ \ s is t : T" and a2: "\ \ \'" and a3: "valid \'" shows "\' \ s is t : T" using a1 a2 a3 proof (induct arbitrary: \' rule: log_equiv.induct) case (2 \ s t \') then show "\' \ s is t : TBase" using algorithmic_monotonicity by auto next case (3 \ s t T\<^sub>1 T\<^sub>2 \') have "\ \ s is t : T\<^sub>1\T\<^sub>2" and "\ \ \'" and "valid \'" by fact+ then show "\' \ s is t : T\<^sub>1\T\<^sub>2" by simp qed (auto) lemma main_lemma: shows "\ \ s is t : T \ valid \ \ \ \ s \ t : T" and "\ \ p \ q : T \ \ \ p is q : T" proof (nominal_induct T arbitrary: \ s t p q rule: ty.strong_induct) case (Arrow T\<^sub>1 T\<^sub>2) { case (1 \ s t) have ih1:"\\ s t. \\ \ s is t : T\<^sub>2; valid \\ \ \ \ s \ t : T\<^sub>2" by fact have ih2:"\\ s t. \ \ s \ t : T\<^sub>1 \ \ \ s is t : T\<^sub>1" by fact have h:"\ \ s is t : T\<^sub>1\T\<^sub>2" by fact obtain x::name where fs:"x\(\,s,t)" by (erule exists_fresh[OF fs_name1]) have "valid \" by fact then have v: "valid ((x,T\<^sub>1)#\)" using fs by auto then have "(x,T\<^sub>1)#\ \ Var x \ Var x : T\<^sub>1" by auto then have "(x,T\<^sub>1)#\ \ Var x is Var x : T\<^sub>1" using ih2 by auto then have "(x,T\<^sub>1)#\ \ App s (Var x) is App t (Var x) : T\<^sub>2" using h v by auto then have "(x,T\<^sub>1)#\ \ App s (Var x) \ App t (Var x) : T\<^sub>2" using ih1 v by auto - then show "\ \ s \ t : T\<^sub>1\T\<^sub>2" using fs by (auto simp add: fresh_prod) + then show "\ \ s \ t : T\<^sub>1\T\<^sub>2" using fs by (auto simp: fresh_prod) next case (2 \ p q) have h: "\ \ p \ q : T\<^sub>1\T\<^sub>2" by fact have ih1:"\\ s t. \ \ s \ t : T\<^sub>2 \ \ \ s is t : T\<^sub>2" by fact have ih2:"\\ s t. \\ \ s is t : T\<^sub>1; valid \\ \ \ \ s \ t : T\<^sub>1" by fact { fix \' s t assume "\ \ \'" and hl:"\' \ s is t : T\<^sub>1" and hk: "valid \'" then have "\' \ p \ q : T\<^sub>1 \ T\<^sub>2" using h algorithmic_monotonicity by auto moreover have "\' \ s \ t : T\<^sub>1" using ih2 hl hk by auto ultimately have "\' \ App p s \ App q t : T\<^sub>2" by auto then have "\' \ App p s is App q t : T\<^sub>2" using ih1 by auto } then show "\ \ p is q : T\<^sub>1\T\<^sub>2" by simp } next case TBase { case 2 have h:"\ \ s \ t : TBase" by fact then have "s \|" and "t \|" using path_equiv_implies_nf by auto then have "s \ s" and "t \ t" by auto then have "\ \ s \ t : TBase" using h by auto then show "\ \ s is t : TBase" by auto } qed (auto elim: alg_path_equiv_implies_valid) corollary corollary_main: assumes a: "\ \ s \ t : T" shows "\ \ s \ t : T" using a main_lemma alg_path_equiv_implies_valid by blast lemma logical_symmetry: assumes a: "\ \ s is t : T" shows "\ \ t is s : T" using a by (nominal_induct arbitrary: \ s t rule: ty.strong_induct) - (auto simp add: algorithmic_symmetry) + (auto simp: algorithmic_symmetry) lemma logical_transitivity: assumes "\ \ s is t : T" "\ \ t is u : T" shows "\ \ s is u : T" using assms proof (nominal_induct arbitrary: \ s t u rule:ty.strong_induct) case TBase then show "\ \ s is u : TBase" by (auto elim: algorithmic_transitivity) next case (Arrow T\<^sub>1 T\<^sub>2 \ s t u) have h1:"\ \ s is t : T\<^sub>1 \ T\<^sub>2" by fact have h2:"\ \ t is u : T\<^sub>1 \ T\<^sub>2" by fact have ih1:"\\ s t u. \\ \ s is t : T\<^sub>1; \ \ t is u : T\<^sub>1\ \ \ \ s is u : T\<^sub>1" by fact have ih2:"\\ s t u. \\ \ s is t : T\<^sub>2; \ \ t is u : T\<^sub>2\ \ \ \ s is u : T\<^sub>2" by fact { fix \' s' u' assume hsub:"\ \ \'" and hl:"\' \ s' is u' : T\<^sub>1" and hk: "valid \'" then have "\' \ u' is s' : T\<^sub>1" using logical_symmetry by blast then have "\' \ u' is u' : T\<^sub>1" using ih1 hl by blast then have "\' \ App t u' is App u u' : T\<^sub>2" using h2 hsub hk by auto moreover have "\' \ App s s' is App t u' : T\<^sub>2" using h1 hsub hl hk by auto ultimately have "\' \ App s s' is App u u' : T\<^sub>2" using ih2 by blast } then show "\ \ s is u : T\<^sub>1 \ T\<^sub>2" by auto qed (auto) lemma logical_weak_head_closure: assumes a: "\ \ s is t : T" and b: "s' \ s" and c: "t' \ t" shows "\ \ s' is t' : T" using a b c algorithmic_weak_head_closure -by (nominal_induct arbitrary: \ s t s' t' rule: ty.strong_induct) - (auto, blast) +proof (nominal_induct arbitrary: \ s t s' t' rule: ty.strong_induct) +next + case (Arrow ty1 ty2) + then show ?case + by (smt (verit, ccfv_threshold) QAR_App log_equiv.simps(3)) +qed auto + lemma logical_weak_head_closure': assumes "\ \ s is t : T" and "s' \ s" shows "\ \ s' is t : T" using assms proof (nominal_induct arbitrary: \ s t s' rule: ty.strong_induct) case (TBase \ s t s') then show ?case by force next case (TUnit \ s t s') then show ?case by auto next case (Arrow T\<^sub>1 T\<^sub>2 \ s t s') have h1:"s' \ s" by fact have ih:"\\ s t s'. \\ \ s is t : T\<^sub>2; s' \ s\ \ \ \ s' is t : T\<^sub>2" by fact have h2:"\ \ s is t : T\<^sub>1\T\<^sub>2" by fact then have hb:"\\' s' t'. \\\' \ valid \' \ \' \ s' is t' : T\<^sub>1 \ (\' \ (App s s') is (App t t') : T\<^sub>2)" by auto { fix \' s\<^sub>2 t\<^sub>2 assume "\ \ \'" and "\' \ s\<^sub>2 is t\<^sub>2 : T\<^sub>1" and "valid \'" then have "\' \ (App s s\<^sub>2) is (App t t\<^sub>2) : T\<^sub>2" using hb by auto moreover have "(App s' s\<^sub>2) \ (App s s\<^sub>2)" using h1 by auto ultimately have "\' \ App s' s\<^sub>2 is App t t\<^sub>2 : T\<^sub>2" using ih by auto } then show "\ \ s' is t : T\<^sub>1\T\<^sub>2" by auto qed abbreviation log_equiv_for_psubsts :: "Ctxt \ Subst \ Subst \ Ctxt \ bool" ("_ \ _ is _ over _" [60,60] 60) where "\' \ \ is \' over \ \ \x T. (x,T) \ set \ \ \' \ \ is \' : T" lemma logical_pseudo_reflexivity: assumes "\' \ t is s over \" - shows "\' \ s is s over \" -proof - - from assms have "\' \ s is t over \" using logical_symmetry by blast - with assms show "\' \ s is s over \" using logical_transitivity by blast -qed + shows "\' \ s is s over \" + by (meson assms logical_symmetry logical_transitivity) lemma logical_subst_monotonicity : fixes \ \' \'' :: Ctxt assumes a: "\' \ \ is \' over \" and b: "\' \ \''" and c: "valid \''" shows "\'' \ \ is \' over \" using a b c logical_monotonicity by blast lemma equiv_subst_ext : assumes h1: "\' \ \ is \' over \" and h2: "\' \ s is t : T" and fs: "x\\" shows "\' \ (x,s)#\ is (x,t)#\' over (x,T)#\" using assms proof - { fix y U assume "(y,U) \ set ((x,T)#\)" moreover { assume "(y,U) \ set [(x,T)]" with h2 have "\' \ ((x,s)#\) is ((x,t)#\') : U" by auto } moreover { assume hl:"(y,U) \ set \" - then have "\ y\\" by (induct \) (auto simp add: fresh_list_cons fresh_atm fresh_prod) - then have hf:"x\ Var y" using fs by (auto simp add: fresh_atm) + then have "\ y\\" by (induct \) (auto simp: fresh_list_cons fresh_atm fresh_prod) + then have hf:"x\ Var y" using fs by (auto simp: fresh_atm) then have "((x,s)#\) = \" "((x,t)#\') = \'" using fresh_psubst_simp by blast+ moreover have "\' \ \ is \' : U" using h1 hl by auto ultimately have "\' \ ((x,s)#\) is ((x,t)#\') : U" by auto } ultimately have "\' \ ((x,s)#\) is ((x,t)#\') : U" by auto } then show "\' \ (x,s)#\ is (x,t)#\' over (x,T)#\" by auto qed theorem fundamental_theorem_1: assumes a1: "\ \ t : T" and a2: "\' \ \ is \' over \" and a3: "valid \'" shows "\' \ \ is \' : T" using a1 a2 a3 proof (nominal_induct \ t T avoiding: \ \' arbitrary: \' rule: typing.strong_induct) case (T_Lam x \ T\<^sub>1 t\<^sub>2 T\<^sub>2 \ \' \') have vc: "x\\" "x\\'" "x\\" by fact+ have asm1: "\' \ \ is \' over \" by fact have ih:"\\ \' \'. \\' \ \ is \' over (x,T\<^sub>1)#\; valid \'\ \ \' \ \2> is \'2> : T\<^sub>2" by fact show "\' \ \2> is \'2> : T\<^sub>1\T\<^sub>2" using vc proof (simp, intro strip) fix \'' s' t' assume sub: "\' \ \''" and asm2: "\''\ s' is t' : T\<^sub>1" and val: "valid \''" from asm1 val sub have "\'' \ \ is \' over \" using logical_subst_monotonicity by blast with asm2 vc have "\'' \ (x,s')#\ is (x,t')#\' over (x,T\<^sub>1)#\" using equiv_subst_ext by blast with ih val have "\'' \ ((x,s')#\)2> is ((x,t')#\')2> : T\<^sub>2" by auto with vc have "\''\\2>[x::=s'] is \'2>[x::=t'] : T\<^sub>2" by (simp add: psubst_subst_psubst) moreover have "App (Lam [x].\2>) s' \ \2>[x::=s']" by auto moreover have "App (Lam [x].\'2>) t' \ \'2>[x::=t']" by auto ultimately show "\''\ App (Lam [x].\2>) s' is App (Lam [x].\'2>) t' : T\<^sub>2" using logical_weak_head_closure by auto qed qed (auto) theorem fundamental_theorem_2: assumes h1: "\ \ s \ t : T" and h2: "\' \ \ is \' over \" and h3: "valid \'" shows "\' \ \ is \' : T" using h1 h2 h3 proof (nominal_induct \ s t T avoiding: \' \ \' rule: def_equiv.strong_induct) case (Q_Refl \ t T \' \ \') - have "\ \ t : T" - and "valid \'" by fact+ - moreover - have "\' \ \ is \' over \" by fact - ultimately show "\' \ \ is \' : T" using fundamental_theorem_1 by blast + then show "\' \ \ is \' : T" using fundamental_theorem_1 + by blast next case (Q_Symm \ t s T \' \ \') - have "\' \ \ is \' over \" - and "valid \'" by fact+ - moreover - have ih: "\ \' \ \'. \\' \ \ is \' over \; valid \'\ \ \' \ \ is \' : T" by fact - ultimately show "\' \ \ is \' : T" using logical_symmetry by blast + then show "\' \ \ is \' : T" using logical_symmetry by blast next case (Q_Trans \ s t T u \' \ \') have ih1: "\ \' \ \'. \\' \ \ is \' over \; valid \'\ \ \' \ \ is \' : T" by fact have ih2: "\ \' \ \'. \\' \ \ is \' over \; valid \'\ \ \' \ \ is \' : T" by fact have h: "\' \ \ is \' over \" and v: "valid \'" by fact+ then have "\' \ \' is \' over \" using logical_pseudo_reflexivity by auto then have "\' \ \' is \' : T" using ih2 v by auto moreover have "\' \ \ is \' : T" using ih1 h v by auto ultimately show "\' \ \ is \' : T" using logical_transitivity by blast next case (Q_Abs x \ T\<^sub>1 s\<^sub>2 t\<^sub>2 T\<^sub>2 \' \ \') have fs:"x\\" by fact have fs2: "x\\" "x\\'" by fact+ have h2: "\' \ \ is \' over \" and h3: "valid \'" by fact+ have ih:"\\' \ \'. \\' \ \ is \' over (x,T\<^sub>1)#\; valid \'\ \ \' \ \2> is \'2> : T\<^sub>2" by fact { fix \'' s' t' assume "\' \ \''" and hl:"\''\ s' is t' : T\<^sub>1" and hk: "valid \''" then have "\'' \ \ is \' over \" using h2 logical_subst_monotonicity by blast then have "\'' \ (x,s')#\ is (x,t')#\' over (x,T\<^sub>1)#\" using equiv_subst_ext hl fs by blast then have "\'' \ ((x,s')#\)2> is ((x,t')#\')2> : T\<^sub>2" using ih hk by blast then have "\''\ \2>[x::=s'] is \'2>[x::=t'] : T\<^sub>2" using fs2 psubst_subst_psubst by auto moreover have "App (Lam [x]. \2>) s' \ \2>[x::=s']" and "App (Lam [x].\'2>) t' \ \'2>[x::=t']" by auto ultimately have "\'' \ App (Lam [x]. \2>) s' is App (Lam [x].\'2>) t' : T\<^sub>2" using logical_weak_head_closure by auto } moreover have "valid \'" by fact ultimately have "\' \ Lam [x].\2> is Lam [x].\'2> : T\<^sub>1\T\<^sub>2" by auto then show "\' \ \2> is \'2> : T\<^sub>1\T\<^sub>2" using fs2 by auto next case (Q_App \ s\<^sub>1 t\<^sub>1 T\<^sub>1 T\<^sub>2 s\<^sub>2 t\<^sub>2 \' \ \') then show "\' \ \1 s\<^sub>2> is \'1 t\<^sub>2> : T\<^sub>2" by auto next case (Q_Beta x \ s\<^sub>2 t\<^sub>2 T\<^sub>1 s12 t12 T\<^sub>2 \' \ \') have h: "\' \ \ is \' over \" and h': "valid \'" by fact+ have fs: "x\\" by fact have fs2: " x\\" "x\\'" by fact+ have ih1: "\\' \ \'. \\' \ \ is \' over \; valid \'\ \ \' \ \2> is \'2> : T\<^sub>1" by fact have ih2: "\\' \ \'. \\' \ \ is \' over (x,T\<^sub>1)#\; valid \'\ \ \' \ \ is \' : T\<^sub>2" by fact have "\' \ \2> is \'2> : T\<^sub>1" using ih1 h' h by auto then have "\' \ (x,\2>)#\ is (x,\'2>)#\' over (x,T\<^sub>1)#\" using equiv_subst_ext h fs by blast then have "\' \ ((x,\2>)#\) is ((x,\'2>)#\') : T\<^sub>2" using ih2 h' by auto then have "\' \ \[x::=\2>] is \'[x::=\'2>] : T\<^sub>2" using fs2 psubst_subst_psubst by auto then have "\' \ \[x::=\2>] is \'2]> : T\<^sub>2" using fs2 psubst_subst_propagate by auto moreover have "App (Lam [x].\) (\2>) \ \[x::=\2>]" by auto ultimately have "\' \ App (Lam [x].\) (\2>) is \'2]> : T\<^sub>2" using logical_weak_head_closure' by auto then show "\' \ \2> is \'2]> : T\<^sub>2" using fs2 by simp next case (Q_Ext x \ s t T\<^sub>1 T\<^sub>2 \' \ \') have h2: "\' \ \ is \' over \" and h2': "valid \'" by fact+ have fs:"x\\" "x\s" "x\t" by fact+ have ih:"\\' \ \'. \\' \ \ is \' over (x,T\<^sub>1)#\; valid \'\ \ \' \ \ is \' : T\<^sub>2" by fact { fix \'' s' t' assume hsub: "\' \ \''" and hl: "\''\ s' is t' : T\<^sub>1" and hk: "valid \''" then have "\'' \ \ is \' over \" using h2 logical_subst_monotonicity by blast then have "\'' \ (x,s')#\ is (x,t')#\' over (x,T\<^sub>1)#\" using equiv_subst_ext hl fs by blast then have "\'' \ ((x,s')#\) is ((x,t')#\') : T\<^sub>2" using ih hk by blast then have "\'' \ App (((x,s')#\)) (((x,s')#\)<(Var x)>) is App (((x,t')#\')) (((x,t')#\')<(Var x)>) : T\<^sub>2" by auto then have "\'' \ App ((x,s')#\) s' is App ((x,t')#\') t' : T\<^sub>2" by auto then have "\'' \ App (\) s' is App (\') t' : T\<^sub>2" using fs fresh_psubst_simp by auto } moreover have "valid \'" by fact ultimately show "\' \ \ is \' : T\<^sub>1\T\<^sub>2" by auto next case (Q_Unit \ s t \' \ \') then show "\' \ \ is \' : TUnit" by auto qed theorem completeness: assumes asm: "\ \ s \ t : T" shows "\ \ s \ t : T" proof - have val: "valid \" using def_equiv_implies_valid asm by simp - moreover - { - fix x T - assume "(x,T) \ set \" "valid \" - then have "\ \ Var x is Var x : T" using main_lemma(2) by blast - } - ultimately have "\ \ [] is [] over \" by auto + then have "\ \ [] is [] over \" + by (simp add: QAP_Var main_lemma(2)) then have "\ \ [] is [] : T" using fundamental_theorem_2 val asm by blast then have "\ \ s is t : T" by simp then show "\ \ s \ t : T" using main_lemma(1) val by simp qed text \We leave soundness as an exercise - just like Crary in the ATS book :-) \\ @{prop[mode=IfThen] "\\ \ s \ t : T; \ \ t : T; \ \ s : T\ \ \ \ s \ t : T"} \\ \<^prop>\\\ \ s \ t : T; \ \ t : T; \ \ s : T\ \ \ \ s \ t : T\ \ end diff --git a/src/HOL/Nominal/Examples/Fsub.thy b/src/HOL/Nominal/Examples/Fsub.thy --- a/src/HOL/Nominal/Examples/Fsub.thy +++ b/src/HOL/Nominal/Examples/Fsub.thy @@ -1,1853 +1,1849 @@ (*<*) theory Fsub imports "HOL-Nominal.Nominal" begin (*>*) text\Authors: Christian Urban, Benjamin Pierce, Dimitrios Vytiniotis Stephanie Weirich Steve Zdancewic Julien Narboux Stefan Berghofer with great help from Markus Wenzel.\ section \Types for Names, Nominal Datatype Declaration for Types and Terms\ no_syntax "_Map" :: "maplets => 'a \ 'b" ("(1[_])") text \The main point of this solution is to use names everywhere (be they bound, binding or free). In System \FSUB{} there are two kinds of names corresponding to type-variables and to term-variables. These two kinds of names are represented in the nominal datatype package as atom-types \tyvrs\ and \vrs\:\ atom_decl tyvrs vrs text\There are numerous facts that come with this declaration: for example that there are infinitely many elements in \tyvrs\ and \vrs\.\ text\The constructors for types and terms in System \FSUB{} contain abstractions over type-variables and term-variables. The nominal datatype package uses \\\\\\ to indicate where abstractions occur.\ nominal_datatype ty = Tvar "tyvrs" | Top | Arrow "ty" "ty" (infixr "\" 200) | Forall "\tyvrs\ty" "ty" nominal_datatype trm = Var "vrs" | Abs "\vrs\trm" "ty" | TAbs "\tyvrs\trm" "ty" | App "trm" "trm" (infixl "\" 200) | TApp "trm" "ty" (infixl "\\<^sub>\" 200) text \To be polite to the eye, some more familiar notation is introduced. Because of the change in the order of arguments, one needs to use translation rules, instead of syntax annotations at the term-constructors as given above for \<^term>\Arrow\.\ abbreviation Forall_syn :: "tyvrs \ ty \ ty \ ty" ("(3\_<:_./ _)" [0, 0, 10] 10) where "\X<:T\<^sub>1. T\<^sub>2 \ ty.Forall X T\<^sub>2 T\<^sub>1" abbreviation Abs_syn :: "vrs \ ty \ trm \ trm" ("(3\_:_./ _)" [0, 0, 10] 10) where "\x:T. t \ trm.Abs x t T" abbreviation TAbs_syn :: "tyvrs \ ty \ trm \ trm" ("(3\_<:_./ _)" [0, 0, 10] 10) where "\X<:T. t \ trm.TAbs X t T" text \Again there are numerous facts that are proved automatically for \<^typ>\ty\ and \<^typ>\trm\: for example that the set of free variables, i.e.~the \support\, is finite. However note that nominal-datatype declarations do \emph{not} define ``classical" constructor-based datatypes, but rather define $\alpha$-equivalence classes---we can for example show that $\alpha$-equivalent \<^typ>\ty\s and \<^typ>\trm\s are equal:\ lemma alpha_illustration: shows "(\X<:T. Tvar X) = (\Y<:T. Tvar Y)" and "(\x:T. Var x) = (\y:T. Var y)" by (simp_all add: ty.inject trm.inject alpha calc_atm fresh_atm) section \SubTyping Contexts\ nominal_datatype binding = VarB vrs ty | TVarB tyvrs ty type_synonym env = "binding list" text \Typing contexts are represented as lists that ``grow" on the left; we thereby deviating from the convention in the POPLmark-paper. The lists contain pairs of type-variables and types (this is sufficient for Part 1A).\ text \In order to state validity-conditions for typing-contexts, the notion of a \dom\ of a typing-context is handy.\ nominal_primrec "tyvrs_of" :: "binding \ tyvrs set" where "tyvrs_of (VarB x y) = {}" | "tyvrs_of (TVarB x y) = {x}" by auto nominal_primrec "vrs_of" :: "binding \ vrs set" where "vrs_of (VarB x y) = {x}" | "vrs_of (TVarB x y) = {}" by auto primrec "ty_dom" :: "env \ tyvrs set" where "ty_dom [] = {}" | "ty_dom (X#\) = (tyvrs_of X)\(ty_dom \)" primrec "trm_dom" :: "env \ vrs set" where "trm_dom [] = {}" | "trm_dom (X#\) = (vrs_of X)\(trm_dom \)" lemma vrs_of_eqvt[eqvt]: fixes pi ::"tyvrs prm" and pi'::"vrs prm" shows "pi \(tyvrs_of x) = tyvrs_of (pi\x)" and "pi'\(tyvrs_of x) = tyvrs_of (pi'\x)" and "pi \(vrs_of x) = vrs_of (pi\x)" and "pi'\(vrs_of x) = vrs_of (pi'\x)" by (nominal_induct x rule: binding.strong_induct) (simp_all add: tyvrs_of.simps eqvts) lemma doms_eqvt[eqvt]: fixes pi::"tyvrs prm" and pi'::"vrs prm" shows "pi \(ty_dom \) = ty_dom (pi\\)" and "pi'\(ty_dom \) = ty_dom (pi'\\)" and "pi \(trm_dom \) = trm_dom (pi\\)" and "pi'\(trm_dom \) = trm_dom (pi'\\)" by (induct \) (simp_all add: eqvts) lemma finite_vrs: shows "finite (tyvrs_of x)" and "finite (vrs_of x)" by (nominal_induct rule:binding.strong_induct) auto lemma finite_doms: shows "finite (ty_dom \)" and "finite (trm_dom \)" by (induct \) (auto simp: finite_vrs) lemma ty_dom_supp: shows "(supp (ty_dom \)) = (ty_dom \)" and "(supp (trm_dom \)) = (trm_dom \)" by (simp only: at_fin_set_supp at_tyvrs_inst at_vrs_inst finite_doms)+ lemma ty_dom_inclusion: assumes a: "(TVarB X T)\set \" shows "X\(ty_dom \)" using a by (induct \) (auto) lemma ty_binding_existence: assumes "X \ (tyvrs_of a)" shows "\T.(TVarB X T=a)" using assms by (nominal_induct a rule: binding.strong_induct) (auto) lemma ty_dom_existence: assumes a: "X\(ty_dom \)" shows "\T.(TVarB X T)\set \" using a proof (induction \) case Nil then show ?case by simp next case (Cons a \) then show ?case using ty_binding_existence by fastforce qed lemma doms_append: shows "ty_dom (\@\) = ((ty_dom \) \ (ty_dom \))" and "trm_dom (\@\) = ((trm_dom \) \ (trm_dom \))" by (induct \) (auto) lemma ty_vrs_prm_simp: fixes pi::"vrs prm" and S::"ty" shows "pi\S = S" by (induct S rule: ty.induct) (auto simp: calc_atm) lemma fresh_ty_dom_cons: fixes X::"tyvrs" shows "X\(ty_dom (Y#\)) = (X\(tyvrs_of Y) \ X\(ty_dom \))" proof (nominal_induct rule:binding.strong_induct) case (VarB vrs ty) then show ?case by auto next case (TVarB tyvrs ty) then show ?case by (simp add: at_fin_set_supp at_tyvrs_inst finite_doms(1) fresh_def supp_atm(1)) qed lemma tyvrs_fresh: fixes X::"tyvrs" assumes "X \ a" shows "X \ tyvrs_of a" and "X \ vrs_of a" using assms by (nominal_induct a rule:binding.strong_induct) (force simp: fresh_singleton)+ lemma fresh_dom: fixes X::"tyvrs" assumes a: "X\\" shows "X\(ty_dom \)" using a proof (induct \) case Nil then show ?case by auto next case (Cons a \) then show ?case by (meson fresh_list_cons fresh_ty_dom_cons tyvrs_fresh(1)) qed text \Not all lists of type \<^typ>\env\ are well-formed. One condition requires that in \<^term>\TVarB X S#\\ all free variables of \<^term>\S\ must be in the \<^term>\ty_dom\ of \<^term>\\\, that is \<^term>\S\ must be \closed\ in \<^term>\\\. The set of free variables of \<^term>\S\ is the \support\ of \<^term>\S\.\ definition "closed_in" :: "ty \ env \ bool" ("_ closed'_in _" [100,100] 100) where "S closed_in \ \ (supp S)\(ty_dom \)" lemma closed_in_eqvt[eqvt]: fixes pi::"tyvrs prm" assumes a: "S closed_in \" shows "(pi\S) closed_in (pi\\)" using a proof - from a have "pi\(S closed_in \)" by (simp add: perm_bool) then show "(pi\S) closed_in (pi\\)" by (simp add: closed_in_def eqvts) qed lemma tyvrs_vrs_prm_simp: fixes pi::"vrs prm" shows "tyvrs_of (pi\a) = tyvrs_of a" by (nominal_induct rule:binding.strong_induct) (auto simp: vrs_prm_tyvrs_def) lemma ty_vrs_fresh: fixes x::"vrs" and T::"ty" shows "x \ T" by (simp add: fresh_def supp_def ty_vrs_prm_simp) lemma ty_dom_vrs_prm_simp: fixes pi::"vrs prm" and \::"env" shows "(ty_dom (pi\\)) = (ty_dom \)" by (induct \) (auto simp: tyvrs_vrs_prm_simp) lemma closed_in_eqvt'[eqvt]: fixes pi::"vrs prm" assumes a: "S closed_in \" shows "(pi\S) closed_in (pi\\)" using assms closed_in_def ty_dom_vrs_prm_simp ty_vrs_prm_simp by force lemma fresh_vrs_of: fixes x::"vrs" shows "x\vrs_of b = x\b" by (nominal_induct b rule: binding.strong_induct) (simp_all add: fresh_singleton fresh_set_empty ty_vrs_fresh fresh_atm) lemma fresh_trm_dom: fixes x::"vrs" shows "x\ trm_dom \ = x\\" by (induct \) (simp_all add: fresh_list_cons fresh_fin_union [OF pt_vrs_inst at_vrs_inst fs_vrs_inst] finite_doms finite_vrs fresh_vrs_of) lemma closed_in_fresh: "(X::tyvrs) \ ty_dom \ \ T closed_in \ \ X \ T" by (auto simp: closed_in_def fresh_def ty_dom_supp) text \Now validity of a context is a straightforward inductive definition.\ inductive valid_rel :: "env \ bool" ("\ _ ok" [100] 100) where valid_nil[simp]: "\ [] ok" | valid_consT[simp]: "\\ \ ok; X\(ty_dom \); T closed_in \\ \ \ (TVarB X T#\) ok" | valid_cons [simp]: "\\ \ ok; x\(trm_dom \); T closed_in \\ \ \ (VarB x T#\) ok" equivariance valid_rel declare binding.inject [simp add] declare trm.inject [simp add] inductive_cases validE[elim]: "\ (TVarB X T#\) ok" "\ (VarB x T#\) ok" "\ (b#\) ok" declare binding.inject [simp del] declare trm.inject [simp del] lemma validE_append: assumes a: "\ (\@\) ok" shows "\ \ ok" using a proof (induct \) case (Cons a \') then show ?case by (nominal_induct a rule:binding.strong_induct) auto qed (auto) lemma replace_type: assumes a: "\ (\@(TVarB X T)#\) ok" and b: "S closed_in \" shows "\ (\@(TVarB X S)#\) ok" using a b proof(induct \) case Nil then show ?case by (auto intro: valid_cons simp add: doms_append closed_in_def) next case (Cons a \') then show ?case by (nominal_induct a rule:binding.strong_induct) (auto intro!: valid_cons simp add: doms_append closed_in_def) qed text \Well-formed contexts have a unique type-binding for a type-variable.\ lemma uniqueness_of_ctxt: fixes \::"env" assumes a: "\ \ ok" and b: "(TVarB X T)\set \" and c: "(TVarB X S)\set \" shows "T=S" using a b c proof (induct) case (valid_consT \ X' T') moreover { fix \'::"env" assume a: "X'\(ty_dom \')" have "\(\T.(TVarB X' T)\(set \'))" using a proof (induct \') case (Cons Y \') thus "\ (\T.(TVarB X' T)\set(Y#\'))" by (simp add: fresh_ty_dom_cons fresh_fin_union[OF pt_tyvrs_inst at_tyvrs_inst fs_tyvrs_inst] finite_vrs finite_doms, auto simp: fresh_atm fresh_singleton) qed (simp) } ultimately show "T=S" by (auto simp: binding.inject) qed (auto) lemma uniqueness_of_ctxt': fixes \::"env" assumes a: "\ \ ok" and b: "(VarB x T)\set \" and c: "(VarB x S)\set \" shows "T=S" using a b c proof (induct) case (valid_cons \ x' T') moreover { fix \'::"env" assume a: "x'\(trm_dom \')" have "\(\T.(VarB x' T)\(set \'))" using a proof (induct \') case (Cons y \') thus "\ (\T.(VarB x' T)\set(y#\'))" by (simp add: fresh_fin_union[OF pt_vrs_inst at_vrs_inst fs_vrs_inst] finite_vrs finite_doms, auto simp: fresh_atm fresh_singleton) qed (simp) } ultimately show "T=S" by (auto simp: binding.inject) qed (auto) section \Size and Capture-Avoiding Substitution for Types\ nominal_primrec size_ty :: "ty \ nat" where "size_ty (Tvar X) = 1" | "size_ty (Top) = 1" | "size_ty (T1 \ T2) = (size_ty T1) + (size_ty T2) + 1" | "X \ T1 \ size_ty (\X<:T1. T2) = (size_ty T1) + (size_ty T2) + 1" by (finite_guess | fresh_guess | simp)+ nominal_primrec subst_ty :: "ty \ tyvrs \ ty \ ty" ("_[_ \ _]\<^sub>\" [300, 0, 0] 300) where "(Tvar X)[Y \ T]\<^sub>\ = (if X=Y then T else Tvar X)" | "(Top)[Y \ T]\<^sub>\ = Top" | "(T\<^sub>1 \ T\<^sub>2)[Y \ T]\<^sub>\ = T\<^sub>1[Y \ T]\<^sub>\ \ T\<^sub>2[Y \ T]\<^sub>\" | "X\(Y,T,T\<^sub>1) \ (\X<:T\<^sub>1. T\<^sub>2)[Y \ T]\<^sub>\ = (\X<:T\<^sub>1[Y \ T]\<^sub>\. T\<^sub>2[Y \ T]\<^sub>\)" by (finite_guess | fresh_guess | simp add: abs_fresh)+ lemma subst_eqvt[eqvt]: fixes pi::"tyvrs prm" and T::"ty" shows "pi\(T[X \ T']\<^sub>\) = (pi\T)[(pi\X) \ (pi\T')]\<^sub>\" by (nominal_induct T avoiding: X T' rule: ty.strong_induct) (perm_simp add: fresh_bij)+ lemma subst_eqvt'[eqvt]: fixes pi::"vrs prm" and T::"ty" shows "pi\(T[X \ T']\<^sub>\) = (pi\T)[(pi\X) \ (pi\T')]\<^sub>\" by (nominal_induct T avoiding: X T' rule: ty.strong_induct) (perm_simp add: fresh_left)+ lemma type_subst_fresh: fixes X::"tyvrs" assumes "X\T" and "X\P" shows "X\T[Y \ P]\<^sub>\" using assms by (nominal_induct T avoiding: X Y P rule:ty.strong_induct) (auto simp: abs_fresh) lemma fresh_type_subst_fresh: assumes "X\T'" shows "X\T[X \ T']\<^sub>\" using assms by (nominal_induct T avoiding: X T' rule: ty.strong_induct) (auto simp: fresh_atm abs_fresh) lemma type_subst_identity: "X\T \ T[X \ U]\<^sub>\ = T" by (nominal_induct T avoiding: X U rule: ty.strong_induct) (simp_all add: fresh_atm abs_fresh) lemma type_substitution_lemma: "X \ Y \ X\L \ M[X \ N]\<^sub>\[Y \ L]\<^sub>\ = M[Y \ L]\<^sub>\[X \ N[Y \ L]\<^sub>\]\<^sub>\" by (nominal_induct M avoiding: X Y N L rule: ty.strong_induct) (auto simp: type_subst_fresh type_subst_identity) lemma type_subst_rename: "Y\T \ ([(Y,X)]\T)[Y \ U]\<^sub>\ = T[X \ U]\<^sub>\" by (nominal_induct T avoiding: X Y U rule: ty.strong_induct) (simp_all add: fresh_atm calc_atm abs_fresh fresh_aux) nominal_primrec subst_tyb :: "binding \ tyvrs \ ty \ binding" ("_[_ \ _]\<^sub>b" [100,100,100] 100) where "(TVarB X U)[Y \ T]\<^sub>b = TVarB X (U[Y \ T]\<^sub>\)" | "(VarB X U)[Y \ T]\<^sub>b = VarB X (U[Y \ T]\<^sub>\)" by auto lemma binding_subst_fresh: fixes X::"tyvrs" assumes "X\a" and "X\P" shows "X\a[Y \ P]\<^sub>b" using assms by (nominal_induct a rule: binding.strong_induct) (auto simp: type_subst_fresh) lemma binding_subst_identity: shows "X\B \ B[X \ U]\<^sub>b = B" by (induct B rule: binding.induct) (simp_all add: fresh_atm type_subst_identity) primrec subst_tyc :: "env \ tyvrs \ ty \ env" ("_[_ \ _]\<^sub>e" [100,100,100] 100) where "([])[Y \ T]\<^sub>e= []" | "(B#\)[Y \ T]\<^sub>e = (B[Y \ T]\<^sub>b)#(\[Y \ T]\<^sub>e)" lemma ctxt_subst_fresh': fixes X::"tyvrs" assumes "X\\" and "X\P" shows "X\\[Y \ P]\<^sub>e" using assms by (induct \) (auto simp: fresh_list_cons binding_subst_fresh) lemma ctxt_subst_mem_TVarB: "TVarB X T \ set \ \ TVarB X (T[Y \ U]\<^sub>\) \ set (\[Y \ U]\<^sub>e)" by (induct \) auto lemma ctxt_subst_mem_VarB: "VarB x T \ set \ \ VarB x (T[Y \ U]\<^sub>\) \ set (\[Y \ U]\<^sub>e)" by (induct \) auto lemma ctxt_subst_identity: "X\\ \ \[X \ U]\<^sub>e = \" by (induct \) (simp_all add: fresh_list_cons binding_subst_identity) lemma ctxt_subst_append: "(\ @ \)[X \ T]\<^sub>e = \[X \ T]\<^sub>e @ \[X \ T]\<^sub>e" by (induct \) simp_all nominal_primrec subst_trm :: "trm \ vrs \ trm \ trm" ("_[_ \ _]" [300, 0, 0] 300) where "(Var x)[y \ t'] = (if x=y then t' else (Var x))" | "(t1 \ t2)[y \ t'] = t1[y \ t'] \ t2[y \ t']" | "(t \\<^sub>\ T)[y \ t'] = t[y \ t'] \\<^sub>\ T" | "X\(T,t') \ (\X<:T. t)[y \ t'] = (\X<:T. t[y \ t'])" | "x\(y,t') \ (\x:T. t)[y \ t'] = (\x:T. t[y \ t'])" -apply(finite_guess)+ -apply(rule TrueI)+ -apply(simp add: abs_fresh)+ -apply(fresh_guess add: ty_vrs_fresh abs_fresh)+ -done + by (finite_guess | simp add: abs_fresh | fresh_guess add: ty_vrs_fresh abs_fresh)+ lemma subst_trm_fresh_tyvar: fixes X::"tyvrs" shows "X\t \ X\u \ X\t[x \ u]" by (nominal_induct t avoiding: x u rule: trm.strong_induct) (auto simp: abs_fresh) lemma subst_trm_fresh_var: "x\u \ x\t[x \ u]" by (nominal_induct t avoiding: x u rule: trm.strong_induct) (simp_all add: abs_fresh fresh_atm ty_vrs_fresh) lemma subst_trm_eqvt[eqvt]: fixes pi::"tyvrs prm" and t::"trm" shows "pi\(t[x \ u]) = (pi\t)[(pi\x) \ (pi\u)]" by (nominal_induct t avoiding: x u rule: trm.strong_induct) (perm_simp add: fresh_left)+ lemma subst_trm_eqvt'[eqvt]: fixes pi::"vrs prm" and t::"trm" shows "pi\(t[x \ u]) = (pi\t)[(pi\x) \ (pi\u)]" by (nominal_induct t avoiding: x u rule: trm.strong_induct) (perm_simp add: fresh_left)+ lemma subst_trm_rename: "y\t \ ([(y, x)] \ t)[y \ u] = t[x \ u]" by (nominal_induct t avoiding: x y u rule: trm.strong_induct) (simp_all add: fresh_atm calc_atm abs_fresh fresh_aux ty_vrs_fresh perm_fresh_fresh) nominal_primrec (freshness_context: "T2::ty") subst_trm_ty :: "trm \ tyvrs \ ty \ trm" ("_[_ \\<^sub>\ _]" [300, 0, 0] 300) where "(Var x)[Y \\<^sub>\ T2] = Var x" | "(t1 \ t2)[Y \\<^sub>\ T2] = t1[Y \\<^sub>\ T2] \ t2[Y \\<^sub>\ T2]" | "(t1 \\<^sub>\ T)[Y \\<^sub>\ T2] = t1[Y \\<^sub>\ T2] \\<^sub>\ T[Y \ T2]\<^sub>\" | "X\(Y,T,T2) \ (\X<:T. t)[Y \\<^sub>\ T2] = (\X<:T[Y \ T2]\<^sub>\. t[Y \\<^sub>\ T2])" | "(\x:T. t)[Y \\<^sub>\ T2] = (\x:T[Y \ T2]\<^sub>\. t[Y \\<^sub>\ T2])" apply(finite_guess | simp add: abs_fresh ty_vrs_fresh type_subst_fresh)+ apply(fresh_guess add: ty_vrs_fresh abs_fresh)+ done lemma subst_trm_ty_fresh: fixes X::"tyvrs" shows "X\t \ X\T \ X\t[Y \\<^sub>\ T]" by (nominal_induct t avoiding: Y T rule: trm.strong_induct) (auto simp: abs_fresh type_subst_fresh) lemma subst_trm_ty_fresh': "X\T \ X\t[X \\<^sub>\ T]" by (nominal_induct t avoiding: X T rule: trm.strong_induct) (simp_all add: abs_fresh fresh_type_subst_fresh fresh_atm) lemma subst_trm_ty_eqvt[eqvt]: fixes pi::"tyvrs prm" and t::"trm" shows "pi\(t[X \\<^sub>\ T]) = (pi\t)[(pi\X) \\<^sub>\ (pi\T)]" by (nominal_induct t avoiding: X T rule: trm.strong_induct) (perm_simp add: fresh_bij subst_eqvt)+ lemma subst_trm_ty_eqvt'[eqvt]: fixes pi::"vrs prm" and t::"trm" shows "pi\(t[X \\<^sub>\ T]) = (pi\t)[(pi\X) \\<^sub>\ (pi\T)]" by (nominal_induct t avoiding: X T rule: trm.strong_induct) (perm_simp add: fresh_left subst_eqvt')+ lemma subst_trm_ty_rename: "Y\t \ ([(Y, X)] \ t)[Y \\<^sub>\ U] = t[X \\<^sub>\ U]" by (nominal_induct t avoiding: X Y U rule: trm.strong_induct) (simp_all add: fresh_atm calc_atm abs_fresh fresh_aux type_subst_rename) section \Subtyping-Relation\ text \The definition for the subtyping-relation follows quite closely what is written in the POPLmark-paper, except for the premises dealing with well-formed contexts and the freshness constraint \<^term>\X\\\ in the \S_Forall\-rule. (The freshness constraint is specific to the \emph{nominal approach}. Note, however, that the constraint does \emph{not} make the subtyping-relation ``partial"\ldots because we work over $\alpha$-equivalence classes.)\ inductive subtype_of :: "env \ ty \ ty \ bool" ("_\_<:_" [100,100,100] 100) where SA_Top[intro]: "\\ \ ok; S closed_in \\ \ \ \ S <: Top" | SA_refl_TVar[intro]: "\\ \ ok; X \ ty_dom \\\ \ \ Tvar X <: Tvar X" | SA_trans_TVar[intro]: "\(TVarB X S) \ set \; \ \ S <: T\ \ \ \ (Tvar X) <: T" | SA_arrow[intro]: "\\ \ T\<^sub>1 <: S\<^sub>1; \ \ S\<^sub>2 <: T\<^sub>2\ \ \ \ (S\<^sub>1 \ S\<^sub>2) <: (T\<^sub>1 \ T\<^sub>2)" | SA_all[intro]: "\\ \ T\<^sub>1 <: S\<^sub>1; ((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: T\<^sub>2\ \ \ \ (\X<:S\<^sub>1. S\<^sub>2) <: (\X<:T\<^sub>1. T\<^sub>2)" lemma subtype_implies_ok: fixes X::"tyvrs" assumes a: "\ \ S <: T" shows "\ \ ok" using a by (induct) (auto) lemma subtype_implies_closed: assumes a: "\ \ S <: T" shows "S closed_in \ \ T closed_in \" using a proof (induct) case (SA_Top \ S) have "Top closed_in \" by (simp add: closed_in_def ty.supp) moreover have "S closed_in \" by fact ultimately show "S closed_in \ \ Top closed_in \" by simp next case (SA_trans_TVar X S \ T) have "(TVarB X S)\set \" by fact hence "X \ ty_dom \" by (rule ty_dom_inclusion) hence "(Tvar X) closed_in \" by (simp add: closed_in_def ty.supp supp_atm) moreover have "S closed_in \ \ T closed_in \" by fact hence "T closed_in \" by force ultimately show "(Tvar X) closed_in \ \ T closed_in \" by simp qed (auto simp: closed_in_def ty.supp supp_atm abs_supp) lemma subtype_implies_fresh: fixes X::"tyvrs" assumes a1: "\ \ S <: T" and a2: "X\\" shows "X\S \ X\T" proof - from a1 have "\ \ ok" by (rule subtype_implies_ok) with a2 have "X\ty_dom(\)" by (simp add: fresh_dom) moreover from a1 have "S closed_in \ \ T closed_in \" by (rule subtype_implies_closed) hence "supp S \ ((supp (ty_dom \))::tyvrs set)" and "supp T \ ((supp (ty_dom \))::tyvrs set)" by (simp_all add: ty_dom_supp closed_in_def) ultimately show "X\S \ X\T" by (force simp: supp_prod fresh_def) qed lemma valid_ty_dom_fresh: fixes X::"tyvrs" assumes valid: "\ \ ok" shows "X\(ty_dom \) = X\\" using valid proof induct case valid_nil then show ?case by auto next case (valid_consT \ X T) then show ?case by (auto simp: fresh_list_cons closed_in_fresh fresh_fin_insert [OF pt_tyvrs_inst at_tyvrs_inst fs_tyvrs_inst] finite_doms) next case (valid_cons \ x T) then show ?case using fresh_atm by (auto simp: fresh_list_cons closed_in_fresh) qed equivariance subtype_of nominal_inductive subtype_of apply (simp_all add: abs_fresh) apply (fastforce simp: valid_ty_dom_fresh dest: subtype_implies_ok) apply (force simp: closed_in_fresh dest: subtype_implies_closed subtype_implies_ok)+ done section \Reflexivity of Subtyping\ lemma subtype_reflexivity: assumes a: "\ \ ok" and b: "T closed_in \" shows "\ \ T <: T" using a b proof(nominal_induct T avoiding: \ rule: ty.strong_induct) case (Forall X T\<^sub>1 T\<^sub>2) have ih_T\<^sub>1: "\\. \\ \ ok; T\<^sub>1 closed_in \\ \ \ \ T\<^sub>1 <: T\<^sub>1" by fact have ih_T\<^sub>2: "\\. \\ \ ok; T\<^sub>2 closed_in \\ \ \ \ T\<^sub>2 <: T\<^sub>2" by fact have fresh_cond: "X\\" by fact hence fresh_ty_dom: "X\(ty_dom \)" by (simp add: fresh_dom) have "(\X<:T\<^sub>2. T\<^sub>1) closed_in \" by fact hence closed\<^sub>T2: "T\<^sub>2 closed_in \" and closed\<^sub>T1: "T\<^sub>1 closed_in ((TVarB X T\<^sub>2)#\)" by (auto simp: closed_in_def ty.supp abs_supp) have ok: "\ \ ok" by fact hence ok': "\ ((TVarB X T\<^sub>2)#\) ok" using closed\<^sub>T2 fresh_ty_dom by simp have "\ \ T\<^sub>2 <: T\<^sub>2" using ih_T\<^sub>2 closed\<^sub>T2 ok by simp moreover have "((TVarB X T\<^sub>2)#\) \ T\<^sub>1 <: T\<^sub>1" using ih_T\<^sub>1 closed\<^sub>T1 ok' by simp ultimately show "\ \ (\X<:T\<^sub>2. T\<^sub>1) <: (\X<:T\<^sub>2. T\<^sub>1)" using fresh_cond by (simp add: subtype_of.SA_all) qed (auto simp: closed_in_def ty.supp supp_atm) lemma subtype_reflexivity_semiautomated: assumes a: "\ \ ok" and b: "T closed_in \" shows "\ \ T <: T" using a b apply(nominal_induct T avoiding: \ rule: ty.strong_induct) apply(auto simp: ty.supp abs_supp supp_atm closed_in_def) \ \Too bad that this instantiation cannot be found automatically by \isakeyword{auto}; \isakeyword{blast} would find it if we had not used an explicit definition for \closed_in_def\.\ apply(drule_tac x="(TVarB tyvrs ty2)#\" in meta_spec) apply(force dest: fresh_dom simp add: closed_in_def) done section \Weakening\ text \In order to prove weakening we introduce the notion of a type-context extending another. This generalization seems to make the proof for weakening to be smoother than if we had strictly adhered to the version in the POPLmark-paper.\ definition extends :: "env \ env \ bool" ("_ extends _" [100,100] 100) where "\ extends \ \ \X Q. (TVarB X Q)\set \ \ (TVarB X Q)\set \" lemma extends_ty_dom: assumes "\ extends \" shows "ty_dom \ \ ty_dom \" using assms by (meson extends_def subsetI ty_dom_existence ty_dom_inclusion) lemma extends_closed: assumes "T closed_in \" and "\ extends \" shows "T closed_in \" by (meson assms closed_in_def extends_ty_dom order.trans) lemma extends_memb: assumes a: "\ extends \" and b: "(TVarB X T) \ set \" shows "(TVarB X T) \ set \" using a b by (simp add: extends_def) lemma weakening: assumes a: "\ \ S <: T" and b: "\ \ ok" and c: "\ extends \" shows "\ \ S <: T" using a b c proof (nominal_induct \ S T avoiding: \ rule: subtype_of.strong_induct) case (SA_Top \ S) have lh_drv_prem: "S closed_in \" by fact have "\ \ ok" by fact moreover have "\ extends \" by fact hence "S closed_in \" using lh_drv_prem by (simp only: extends_closed) ultimately show "\ \ S <: Top" by force next case (SA_trans_TVar X S \ T) have lh_drv_prem: "(TVarB X S) \ set \" by fact have ih: "\\. \ \ ok \ \ extends \ \ \ \ S <: T" by fact have ok: "\ \ ok" by fact have extends: "\ extends \" by fact have "(TVarB X S) \ set \" using lh_drv_prem extends by (simp only: extends_memb) moreover have "\ \ S <: T" using ok extends ih by simp ultimately show "\ \ Tvar X <: T" using ok by force next case (SA_refl_TVar \ X) have lh_drv_prem: "X \ ty_dom \" by fact have "\ \ ok" by fact moreover have "\ extends \" by fact hence "X \ ty_dom \" using lh_drv_prem by (force dest: extends_ty_dom) ultimately show "\ \ Tvar X <: Tvar X" by force next case (SA_arrow \ T\<^sub>1 S\<^sub>1 S\<^sub>2 T\<^sub>2) thus "\ \ S\<^sub>1 \ S\<^sub>2 <: T\<^sub>1 \ T\<^sub>2" by blast next case (SA_all \ T\<^sub>1 S\<^sub>1 X S\<^sub>2 T\<^sub>2) have fresh_cond: "X\\" by fact hence fresh_dom: "X\(ty_dom \)" by (simp add: fresh_dom) have ih\<^sub>1: "\\. \ \ ok \ \ extends \ \ \ \ T\<^sub>1 <: S\<^sub>1" by fact have ih\<^sub>2: "\\. \ \ ok \ \ extends ((TVarB X T\<^sub>1)#\) \ \ \ S\<^sub>2 <: T\<^sub>2" by fact have lh_drv_prem: "\ \ T\<^sub>1 <: S\<^sub>1" by fact hence closed\<^sub>T1: "T\<^sub>1 closed_in \" by (simp add: subtype_implies_closed) have ok: "\ \ ok" by fact have ext: "\ extends \" by fact have "T\<^sub>1 closed_in \" using ext closed\<^sub>T1 by (simp only: extends_closed) hence "\ ((TVarB X T\<^sub>1)#\) ok" using fresh_dom ok by force moreover have "((TVarB X T\<^sub>1)#\) extends ((TVarB X T\<^sub>1)#\)" using ext by (force simp: extends_def) ultimately have "((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: T\<^sub>2" using ih\<^sub>2 by simp moreover have "\ \ T\<^sub>1 <: S\<^sub>1" using ok ext ih\<^sub>1 by simp ultimately show "\ \ (\X<:S\<^sub>1. S\<^sub>2) <: (\X<:T\<^sub>1. T\<^sub>2)" using ok by (force intro: SA_all) qed text \In fact all ``non-binding" cases can be solved automatically:\ lemma weakening_more_automated: assumes a: "\ \ S <: T" and b: "\ \ ok" and c: "\ extends \" shows "\ \ S <: T" using a b c proof (nominal_induct \ S T avoiding: \ rule: subtype_of.strong_induct) case (SA_all \ T\<^sub>1 S\<^sub>1 X S\<^sub>2 T\<^sub>2) have fresh_cond: "X\\" by fact hence fresh_dom: "X\(ty_dom \)" by (simp add: fresh_dom) have ih\<^sub>1: "\\. \ \ ok \ \ extends \ \ \ \ T\<^sub>1 <: S\<^sub>1" by fact have ih\<^sub>2: "\\. \ \ ok \ \ extends ((TVarB X T\<^sub>1)#\) \ \ \ S\<^sub>2 <: T\<^sub>2" by fact have lh_drv_prem: "\ \ T\<^sub>1 <: S\<^sub>1" by fact hence closed\<^sub>T1: "T\<^sub>1 closed_in \" by (simp add: subtype_implies_closed) have ok: "\ \ ok" by fact have ext: "\ extends \" by fact have "T\<^sub>1 closed_in \" using ext closed\<^sub>T1 by (simp only: extends_closed) hence "\ ((TVarB X T\<^sub>1)#\) ok" using fresh_dom ok by force moreover have "((TVarB X T\<^sub>1)#\) extends ((TVarB X T\<^sub>1)#\)" using ext by (force simp: extends_def) ultimately have "((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: T\<^sub>2" using ih\<^sub>2 by simp moreover have "\ \ T\<^sub>1 <: S\<^sub>1" using ok ext ih\<^sub>1 by simp ultimately show "\ \ (\X<:S\<^sub>1. S\<^sub>2) <: (\X<:T\<^sub>1. T\<^sub>2)" using ok by (force intro: SA_all) qed (blast intro: extends_closed extends_memb dest: extends_ty_dom)+ section \Transitivity and Narrowing\ text \Some inversion lemmas that are needed in the transitivity and narrowing proof.\ declare ty.inject [simp add] inductive_cases S_TopE: "\ \ Top <: T" inductive_cases S_ArrowE_left: "\ \ S\<^sub>1 \ S\<^sub>2 <: T" declare ty.inject [simp del] lemma S_ForallE_left: shows "\\ \ (\X<:S\<^sub>1. S\<^sub>2) <: T; X\\; X\S\<^sub>1; X\T\ \ T = Top \ (\T\<^sub>1 T\<^sub>2. T = (\X<:T\<^sub>1. T\<^sub>2) \ \ \ T\<^sub>1 <: S\<^sub>1 \ ((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: T\<^sub>2)" using subtype_of.strong_cases[where X="X"] by(force simp: abs_fresh ty.inject alpha) text \Next we prove the transitivity and narrowing for the subtyping-relation. The POPLmark-paper says the following: \begin{quote} \begin{lemma}[Transitivity and Narrowing] \ \begin{enumerate} \item If \<^term>\\ \ S<:Q\ and \<^term>\\ \ Q<:T\, then \<^term>\\ \ S<:T\. \item If \\,X<:Q,\ \ M<:N\ and \<^term>\\ \ P<:Q\ then \\,X<:P,\ \ M<:N\. \end{enumerate} \end{lemma} The two parts are proved simultaneously, by induction on the size of \<^term>\Q\. The argument for part (2) assumes that part (1) has been established already for the \<^term>\Q\ in question; part (1) uses part (2) only for strictly smaller \<^term>\Q\. \end{quote} For the induction on the size of \<^term>\Q\, we use the induction-rule \measure_induct_rule\: \begin{center} @{thm measure_induct_rule[of "size_ty",no_vars]} \end{center} That means in order to show a property \<^term>\P a\ for all \<^term>\a\, the induct-rule requires to prove that for all \<^term>\x\ \<^term>\P x\ holds using the assumption that for all \<^term>\y\ whose size is strictly smaller than that of \<^term>\x\ the property \<^term>\P y\ holds.\ lemma shows subtype_transitivity: "\\S<:Q \ \\Q<:T \ \\S<:T" and subtype_narrow: "(\@[(TVarB X Q)]@\)\M<:N \ \\P<:Q \ (\@[(TVarB X P)]@\)\M<:N" proof (induct Q arbitrary: \ S T \ X P M N taking: "size_ty" rule: measure_induct_rule) case (less Q) have IH_trans: "\Q' \ S T. \size_ty Q' < size_ty Q; \\S<:Q'; \\Q'<:T\ \ \\S<:T" by fact have IH_narrow: "\Q' \ \ X M N P. \size_ty Q' < size_ty Q; (\@[(TVarB X Q')]@\)\M<:N; \\P<:Q'\ \ (\@[(TVarB X P)]@\)\M<:N" by fact { fix \ S T have "\\ \ S <: Q; \ \ Q <: T\ \ \ \ S <: T" proof (induct \ S Q\Q rule: subtype_of.induct) case (SA_Top \ S) then have rh_drv: "\ \ Top <: T" by simp then have T_inst: "T = Top" by (auto elim: S_TopE) from \\ \ ok\ and \S closed_in \\ have "\ \ S <: Top" by auto then show "\ \ S <: T" using T_inst by simp next case (SA_trans_TVar Y U \) then have IH_inner: "\ \ U <: T" by simp have "(TVarB Y U) \ set \" by fact with IH_inner show "\ \ Tvar Y <: T" by auto next case (SA_refl_TVar \ X) then show "\ \ Tvar X <: T" by simp next case (SA_arrow \ Q\<^sub>1 S\<^sub>1 S\<^sub>2 Q\<^sub>2) then have rh_drv: "\ \ Q\<^sub>1 \ Q\<^sub>2 <: T" by simp from \Q\<^sub>1 \ Q\<^sub>2 = Q\ have Q\<^sub>12_less: "size_ty Q\<^sub>1 < size_ty Q" "size_ty Q\<^sub>2 < size_ty Q" by auto have lh_drv_prm\<^sub>1: "\ \ Q\<^sub>1 <: S\<^sub>1" by fact have lh_drv_prm\<^sub>2: "\ \ S\<^sub>2 <: Q\<^sub>2" by fact from rh_drv have "T=Top \ (\T\<^sub>1 T\<^sub>2. T=T\<^sub>1\T\<^sub>2 \ \\T\<^sub>1<:Q\<^sub>1 \ \\Q\<^sub>2<:T\<^sub>2)" by (auto elim: S_ArrowE_left) moreover have "S\<^sub>1 closed_in \" and "S\<^sub>2 closed_in \" using lh_drv_prm\<^sub>1 lh_drv_prm\<^sub>2 by (simp_all add: subtype_implies_closed) hence "(S\<^sub>1 \ S\<^sub>2) closed_in \" by (simp add: closed_in_def ty.supp) moreover have "\ \ ok" using rh_drv by (rule subtype_implies_ok) moreover { assume "\T\<^sub>1 T\<^sub>2. T = T\<^sub>1\T\<^sub>2 \ \ \ T\<^sub>1 <: Q\<^sub>1 \ \ \ Q\<^sub>2 <: T\<^sub>2" then obtain T\<^sub>1 T\<^sub>2 where T_inst: "T = T\<^sub>1 \ T\<^sub>2" and rh_drv_prm\<^sub>1: "\ \ T\<^sub>1 <: Q\<^sub>1" and rh_drv_prm\<^sub>2: "\ \ Q\<^sub>2 <: T\<^sub>2" by force from IH_trans[of "Q\<^sub>1"] have "\ \ T\<^sub>1 <: S\<^sub>1" using Q\<^sub>12_less rh_drv_prm\<^sub>1 lh_drv_prm\<^sub>1 by simp moreover from IH_trans[of "Q\<^sub>2"] have "\ \ S\<^sub>2 <: T\<^sub>2" using Q\<^sub>12_less rh_drv_prm\<^sub>2 lh_drv_prm\<^sub>2 by simp ultimately have "\ \ S\<^sub>1 \ S\<^sub>2 <: T\<^sub>1 \ T\<^sub>2" by auto then have "\ \ S\<^sub>1 \ S\<^sub>2 <: T" using T_inst by simp } ultimately show "\ \ S\<^sub>1 \ S\<^sub>2 <: T" by blast next case (SA_all \ Q\<^sub>1 S\<^sub>1 X S\<^sub>2 Q\<^sub>2) then have rh_drv: "\ \ (\X<:Q\<^sub>1. Q\<^sub>2) <: T" by simp have lh_drv_prm\<^sub>1: "\ \ Q\<^sub>1 <: S\<^sub>1" by fact have lh_drv_prm\<^sub>2: "((TVarB X Q\<^sub>1)#\) \ S\<^sub>2 <: Q\<^sub>2" by fact then have "X\\" by (force dest: subtype_implies_ok simp add: valid_ty_dom_fresh) then have fresh_cond: "X\\" "X\Q\<^sub>1" "X\T" using rh_drv lh_drv_prm\<^sub>1 by (simp_all add: subtype_implies_fresh) from rh_drv have "T = Top \ (\T\<^sub>1 T\<^sub>2. T = (\X<:T\<^sub>1. T\<^sub>2) \ \ \ T\<^sub>1 <: Q\<^sub>1 \ ((TVarB X T\<^sub>1)#\) \ Q\<^sub>2 <: T\<^sub>2)" using fresh_cond by (simp add: S_ForallE_left) moreover have "S\<^sub>1 closed_in \" and "S\<^sub>2 closed_in ((TVarB X Q\<^sub>1)#\)" using lh_drv_prm\<^sub>1 lh_drv_prm\<^sub>2 by (simp_all add: subtype_implies_closed) then have "(\X<:S\<^sub>1. S\<^sub>2) closed_in \" by (force simp: closed_in_def ty.supp abs_supp) moreover have "\ \ ok" using rh_drv by (rule subtype_implies_ok) moreover { assume "\T\<^sub>1 T\<^sub>2. T=(\X<:T\<^sub>1. T\<^sub>2) \ \\T\<^sub>1<:Q\<^sub>1 \ ((TVarB X T\<^sub>1)#\)\Q\<^sub>2<:T\<^sub>2" then obtain T\<^sub>1 T\<^sub>2 where T_inst: "T = (\X<:T\<^sub>1. T\<^sub>2)" and rh_drv_prm\<^sub>1: "\ \ T\<^sub>1 <: Q\<^sub>1" and rh_drv_prm\<^sub>2:"((TVarB X T\<^sub>1)#\) \ Q\<^sub>2 <: T\<^sub>2" by force have "(\X<:Q\<^sub>1. Q\<^sub>2) = Q" by fact then have Q\<^sub>12_less: "size_ty Q\<^sub>1 < size_ty Q" "size_ty Q\<^sub>2 < size_ty Q" using fresh_cond by auto from IH_trans[of "Q\<^sub>1"] have "\ \ T\<^sub>1 <: S\<^sub>1" using lh_drv_prm\<^sub>1 rh_drv_prm\<^sub>1 Q\<^sub>12_less by blast moreover from IH_narrow[of "Q\<^sub>1" "[]"] have "((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: Q\<^sub>2" using Q\<^sub>12_less lh_drv_prm\<^sub>2 rh_drv_prm\<^sub>1 by simp with IH_trans[of "Q\<^sub>2"] have "((TVarB X T\<^sub>1)#\) \ S\<^sub>2 <: T\<^sub>2" using Q\<^sub>12_less rh_drv_prm\<^sub>2 by simp ultimately have "\ \ (\X<:S\<^sub>1. S\<^sub>2) <: (\X<:T\<^sub>1. T\<^sub>2)" using fresh_cond by (simp add: subtype_of.SA_all) hence "\ \ (\X<:S\<^sub>1. S\<^sub>2) <: T" using T_inst by simp } ultimately show "\ \ (\X<:S\<^sub>1. S\<^sub>2) <: T" by blast qed } note transitivity_lemma = this { \ \The transitivity proof is now by the auxiliary lemma.\ case 1 from \\ \ S <: Q\ and \\ \ Q <: T\ show "\ \ S <: T" by (rule transitivity_lemma) next case 2 from \(\@[(TVarB X Q)]@\) \ M <: N\ and \\ \ P<:Q\ show "(\@[(TVarB X P)]@\) \ M <: N" proof (induct "\@[(TVarB X Q)]@\" M N arbitrary: \ X \ rule: subtype_of.induct) case (SA_Top S \ X \) from \\ \ P <: Q\ have "P closed_in \" by (simp add: subtype_implies_closed) with \\ (\@[(TVarB X Q)]@\) ok\ have "\ (\@[(TVarB X P)]@\) ok" by (simp add: replace_type) moreover from \S closed_in (\@[(TVarB X Q)]@\)\ have "S closed_in (\@[(TVarB X P)]@\)" by (simp add: closed_in_def doms_append) ultimately show "(\@[(TVarB X P)]@\) \ S <: Top" by (simp add: subtype_of.SA_Top) next case (SA_trans_TVar Y S N \ X \) then have IH_inner: "(\@[(TVarB X P)]@\) \ S <: N" and lh_drv_prm: "(TVarB Y S) \ set (\@[(TVarB X Q)]@\)" and rh_drv: "\ \ P<:Q" and ok\<^sub>Q: "\ (\@[(TVarB X Q)]@\) ok" by (simp_all add: subtype_implies_ok) then have ok\<^sub>P: "\ (\@[(TVarB X P)]@\) ok" by (simp add: subtype_implies_ok) show "(\@[(TVarB X P)]@\) \ Tvar Y <: N" proof (cases "X=Y") case False have "X\Y" by fact hence "(TVarB Y S)\set (\@[(TVarB X P)]@\)" using lh_drv_prm by (simp add:binding.inject) with IH_inner show "(\@[(TVarB X P)]@\) \ Tvar Y <: N" by (simp add: subtype_of.SA_trans_TVar) next case True have memb\<^sub>XQ: "(TVarB X Q)\set (\@[(TVarB X Q)]@\)" by simp have memb\<^sub>XP: "(TVarB X P)\set (\@[(TVarB X P)]@\)" by simp have eq: "X=Y" by fact hence "S=Q" using ok\<^sub>Q lh_drv_prm memb\<^sub>XQ by (simp only: uniqueness_of_ctxt) hence "(\@[(TVarB X P)]@\) \ Q <: N" using IH_inner by simp moreover have "(\@[(TVarB X P)]@\) extends \" by (simp add: extends_def) hence "(\@[(TVarB X P)]@\) \ P <: Q" using rh_drv ok\<^sub>P by (simp only: weakening) ultimately have "(\@[(TVarB X P)]@\) \ P <: N" by (simp add: transitivity_lemma) then show "(\@[(TVarB X P)]@\) \ Tvar Y <: N" using memb\<^sub>XP eq by auto qed next case (SA_refl_TVar Y \ X \) from \\ \ P <: Q\ have "P closed_in \" by (simp add: subtype_implies_closed) with \\ (\@[(TVarB X Q)]@\) ok\ have "\ (\@[(TVarB X P)]@\) ok" by (simp add: replace_type) moreover from \Y \ ty_dom (\@[(TVarB X Q)]@\)\ have "Y \ ty_dom (\@[(TVarB X P)]@\)" by (simp add: doms_append) ultimately show "(\@[(TVarB X P)]@\) \ Tvar Y <: Tvar Y" by (simp add: subtype_of.SA_refl_TVar) next case (SA_arrow S\<^sub>1 Q\<^sub>1 Q\<^sub>2 S\<^sub>2 \ X \) then show "(\@[(TVarB X P)]@\) \ Q\<^sub>1 \ Q\<^sub>2 <: S\<^sub>1 \ S\<^sub>2" by blast next case (SA_all T\<^sub>1 S\<^sub>1 Y S\<^sub>2 T\<^sub>2 \ X \) have IH_inner\<^sub>1: "(\@[(TVarB X P)]@\) \ T\<^sub>1 <: S\<^sub>1" and IH_inner\<^sub>2: "(((TVarB Y T\<^sub>1)#\)@[(TVarB X P)]@\) \ S\<^sub>2 <: T\<^sub>2" by (fastforce intro: SA_all)+ then show "(\@[(TVarB X P)]@\) \ (\Y<:S\<^sub>1. S\<^sub>2) <: (\Y<:T\<^sub>1. T\<^sub>2)" by auto qed } qed section \Typing\ inductive typing :: "env \ trm \ ty \ bool" ("_ \ _ : _" [60,60,60] 60) where T_Var[intro]: "\ VarB x T \ set \; \ \ ok \ \ \ \ Var x : T" | T_App[intro]: "\ \ \ t\<^sub>1 : T\<^sub>1 \ T\<^sub>2; \ \ t\<^sub>2 : T\<^sub>1 \ \ \ \ t\<^sub>1 \ t\<^sub>2 : T\<^sub>2" | T_Abs[intro]: "\ VarB x T\<^sub>1 # \ \ t\<^sub>2 : T\<^sub>2 \ \ \ \ (\x:T\<^sub>1. t\<^sub>2) : T\<^sub>1 \ T\<^sub>2" | T_Sub[intro]: "\ \ \ t : S; \ \ S <: T \ \ \ \ t : T" | T_TAbs[intro]:"\ TVarB X T\<^sub>1 # \ \ t\<^sub>2 : T\<^sub>2 \ \ \ \ (\X<:T\<^sub>1. t\<^sub>2) : (\X<:T\<^sub>1. T\<^sub>2)" | T_TApp[intro]:"\X\(\,t\<^sub>1,T\<^sub>2); \ \ t\<^sub>1 : (\X<:T\<^sub>11. T\<^sub>12); \ \ T\<^sub>2 <: T\<^sub>11\ \ \ \ t\<^sub>1 \\<^sub>\ T\<^sub>2 : (T\<^sub>12[X \ T\<^sub>2]\<^sub>\)" equivariance typing lemma better_T_TApp: assumes H1: "\ \ t\<^sub>1 : (\X<:T11. T12)" and H2: "\ \ T2 <: T11" shows "\ \ t\<^sub>1 \\<^sub>\ T2 : (T12[X \ T2]\<^sub>\)" proof - obtain Y::tyvrs where Y: "Y \ (X, T12, \, t\<^sub>1, T2)" by (rule exists_fresh) (rule fin_supp) then have "Y \ (\, t\<^sub>1, T2)" by simp moreover from Y have "(\X<:T11. T12) = (\Y<:T11. [(Y, X)] \ T12)" by (auto simp: ty.inject alpha' fresh_prod fresh_atm) with H1 have "\ \ t\<^sub>1 : (\Y<:T11. [(Y, X)] \ T12)" by simp ultimately have "\ \ t\<^sub>1 \\<^sub>\ T2 : (([(Y, X)] \ T12)[Y \ T2]\<^sub>\)" using H2 by (rule T_TApp) with Y show ?thesis by (simp add: type_subst_rename) qed lemma typing_ok: assumes "\ \ t : T" shows "\ \ ok" using assms by (induct) (auto) nominal_inductive typing by (auto dest!: typing_ok intro: closed_in_fresh fresh_dom type_subst_fresh simp: abs_fresh fresh_type_subst_fresh ty_vrs_fresh valid_ty_dom_fresh fresh_trm_dom) lemma ok_imp_VarB_closed_in: assumes ok: "\ \ ok" shows "VarB x T \ set \ \ T closed_in \" using ok by induct (auto simp: binding.inject closed_in_def) lemma tyvrs_of_subst: "tyvrs_of (B[X \ T]\<^sub>b) = tyvrs_of B" by (nominal_induct B rule: binding.strong_induct) simp_all lemma ty_dom_subst: "ty_dom (\[X \ T]\<^sub>e) = ty_dom \" by (induct \) (simp_all add: tyvrs_of_subst) lemma vrs_of_subst: "vrs_of (B[X \ T]\<^sub>b) = vrs_of B" by (nominal_induct B rule: binding.strong_induct) simp_all lemma trm_dom_subst: "trm_dom (\[X \ T]\<^sub>e) = trm_dom \" by (induct \) (simp_all add: vrs_of_subst) lemma subst_closed_in: "T closed_in (\ @ TVarB X S # \) \ U closed_in \ \ T[X \ U]\<^sub>\ closed_in (\[X \ U]\<^sub>e @ \)" proof (nominal_induct T avoiding: X U \ rule: ty.strong_induct) case (Tvar tyvrs) then show ?case by (auto simp add: closed_in_def ty.supp supp_atm doms_append ty_dom_subst) next case Top then show ?case using closed_in_def fresh_def by fastforce next case (Arrow ty1 ty2) then show ?case by (simp add: closed_in_def ty.supp) next case (Forall tyvrs ty1 ty2) then have "supp (ty1[X \ U]\<^sub>\) \ ty_dom (\[X \ U]\<^sub>e @ TVarB tyvrs ty2 # \)" apply (simp add: closed_in_def ty.supp abs_supp) by (metis Diff_subset_conv Un_left_commute doms_append(1) le_supI2 ty_dom.simps(2) tyvrs_of.simps(2)) with Forall show ?case by (auto simp add: closed_in_def ty.supp abs_supp doms_append) qed lemmas subst_closed_in' = subst_closed_in [where \="[]", simplified] lemma typing_closed_in: assumes "\ \ t : T" shows "T closed_in \" using assms proof induct case (T_Var x T \) from \\ \ ok\ and \VarB x T \ set \\ show ?case by (rule ok_imp_VarB_closed_in) next case (T_App \ t\<^sub>1 T\<^sub>1 T\<^sub>2 t\<^sub>2) then show ?case by (auto simp: ty.supp closed_in_def) next case (T_Abs x T\<^sub>1 \ t\<^sub>2 T\<^sub>2) from \VarB x T\<^sub>1 # \ \ t\<^sub>2 : T\<^sub>2\ have "T\<^sub>1 closed_in \" by (auto dest: typing_ok) with T_Abs show ?case by (auto simp: ty.supp closed_in_def) next case (T_Sub \ t S T) from \\ \ S <: T\ show ?case by (simp add: subtype_implies_closed) next case (T_TAbs X T\<^sub>1 \ t\<^sub>2 T\<^sub>2) from \TVarB X T\<^sub>1 # \ \ t\<^sub>2 : T\<^sub>2\ have "T\<^sub>1 closed_in \" by (auto dest: typing_ok) with T_TAbs show ?case by (auto simp: ty.supp closed_in_def abs_supp) next case (T_TApp X \ t\<^sub>1 T2 T11 T12) then have "T12 closed_in (TVarB X T11 # \)" by (auto simp: closed_in_def ty.supp abs_supp) moreover from T_TApp have "T2 closed_in \" by (simp add: subtype_implies_closed) ultimately show ?case by (rule subst_closed_in') qed subsection \Evaluation\ inductive val :: "trm \ bool" where Abs[intro]: "val (\x:T. t)" | TAbs[intro]: "val (\X<:T. t)" equivariance val inductive_cases val_inv_auto[elim]: "val (Var x)" "val (t1 \ t2)" "val (t1 \\<^sub>\ t2)" inductive eval :: "trm \ trm \ bool" ("_ \ _" [60,60] 60) where E_Abs : "\ x \ v\<^sub>2; val v\<^sub>2 \ \ (\x:T\<^sub>11. t\<^sub>12) \ v\<^sub>2 \ t\<^sub>12[x \ v\<^sub>2]" | E_App1 [intro]: "t \ t' \ t \ u \ t' \ u" | E_App2 [intro]: "\ val v; t \ t' \ \ v \ t \ v \ t'" | E_TAbs : "X \ (T\<^sub>11, T\<^sub>2) \ (\X<:T\<^sub>11. t\<^sub>12) \\<^sub>\ T\<^sub>2 \ t\<^sub>12[X \\<^sub>\ T\<^sub>2]" | E_TApp [intro]: "t \ t' \ t \\<^sub>\ T \ t' \\<^sub>\ T" lemma better_E_Abs[intro]: assumes H: "val v2" shows "(\x:T11. t12) \ v2 \ t12[x \ v2]" proof - obtain y::vrs where y: "y \ (x, t12, v2)" by (rule exists_fresh) (rule fin_supp) then have "y \ v2" by simp then have "(\y:T11. [(y, x)] \ t12) \ v2 \ ([(y, x)] \ t12)[y \ v2]" using H by (rule E_Abs) moreover from y have "(\x:T11. t12) \ v2 = (\y:T11. [(y, x)] \ t12) \ v2" by (auto simp: trm.inject alpha' fresh_prod fresh_atm) ultimately have "(\x:T11. t12) \ v2 \ ([(y, x)] \ t12)[y \ v2]" by simp with y show ?thesis by (simp add: subst_trm_rename) qed lemma better_E_TAbs[intro]: "(\X<:T11. t12) \\<^sub>\ T2 \ t12[X \\<^sub>\ T2]" proof - obtain Y::tyvrs where Y: "Y \ (X, t12, T11, T2)" by (rule exists_fresh) (rule fin_supp) then have "Y \ (T11, T2)" by simp then have "(\Y<:T11. [(Y, X)] \ t12) \\<^sub>\ T2 \ ([(Y, X)] \ t12)[Y \\<^sub>\ T2]" by (rule E_TAbs) moreover from Y have "(\X<:T11. t12) \\<^sub>\ T2 = (\Y<:T11. [(Y, X)] \ t12) \\<^sub>\ T2" by (auto simp: trm.inject alpha' fresh_prod fresh_atm) ultimately have "(\X<:T11. t12) \\<^sub>\ T2 \ ([(Y, X)] \ t12)[Y \\<^sub>\ T2]" by simp with Y show ?thesis by (simp add: subst_trm_ty_rename) qed equivariance eval nominal_inductive eval by (simp_all add: abs_fresh ty_vrs_fresh subst_trm_fresh_tyvar subst_trm_fresh_var subst_trm_ty_fresh') inductive_cases eval_inv_auto[elim]: "Var x \ t'" "(\x:T. t) \ t'" "(\X<:T. t) \ t'" lemma ty_dom_cons: shows "ty_dom (\@[VarB X Q]@\) = ty_dom (\@\)" by (induct \) (auto) lemma closed_in_cons: assumes "S closed_in (\ @ VarB X Q # \)" shows "S closed_in (\@\)" using assms ty_dom_cons closed_in_def by auto lemma closed_in_weaken: "T closed_in (\ @ \) \ T closed_in (\ @ B # \)" by (auto simp: closed_in_def doms_append) lemma closed_in_weaken': "T closed_in \ \ T closed_in (\ @ \)" by (auto simp: closed_in_def doms_append) lemma valid_subst: assumes ok: "\ (\ @ TVarB X Q # \) ok" and closed: "P closed_in \" shows "\ (\[X \ P]\<^sub>e @ \) ok" using ok closed proof (induct \) case Nil then show ?case by auto next case (Cons a \) then have *: "\ (a # \ @ TVarB X Q # \) ok" by fastforce then show ?case apply (rule validE) using Cons apply (simp add: at_tyvrs_inst closed doms_append(1) finite_doms(1) fresh_fin_insert fs_tyvrs_inst pt_tyvrs_inst subst_closed_in ty_dom_subst) by (simp add: doms_append(2) subst_closed_in Cons.hyps closed trm_dom_subst) qed lemma ty_dom_vrs: shows "ty_dom (G @ [VarB x Q] @ D) = ty_dom (G @ D)" by (induct G) (auto) lemma valid_cons': assumes "\ (\ @ VarB x Q # \) ok" shows "\ (\ @ \) ok" using assms proof (induct "\ @ VarB x Q # \" arbitrary: \ \) case valid_nil have "[] = \ @ VarB x Q # \" by fact then have "False" by auto then show ?case by auto next case (valid_consT G X T) then show ?case proof (cases \) case Nil with valid_consT show ?thesis by simp next case (Cons b bs) with valid_consT have "\ (bs @ \) ok" by simp moreover from Cons and valid_consT have "X \ ty_dom (bs @ \)" by (simp add: doms_append) moreover from Cons and valid_consT have "T closed_in (bs @ \)" by (simp add: closed_in_def doms_append) ultimately have "\ (TVarB X T # bs @ \) ok" by (rule valid_rel.valid_consT) with Cons and valid_consT show ?thesis by simp qed next case (valid_cons G x T) then show ?case proof (cases \) case Nil with valid_cons show ?thesis by simp next case (Cons b bs) with valid_cons have "\ (bs @ \) ok" by simp moreover from Cons and valid_cons have "x \ trm_dom (bs @ \)" by (simp add: doms_append finite_doms fresh_fin_insert [OF pt_vrs_inst at_vrs_inst fs_vrs_inst]) moreover from Cons and valid_cons have "T closed_in (bs @ \)" by (simp add: closed_in_def doms_append) ultimately have "\ (VarB x T # bs @ \) ok" by (rule valid_rel.valid_cons) with Cons and valid_cons show ?thesis by simp qed qed text \A.5(6)\ lemma type_weaken: assumes "(\@\) \ t : T" and "\ (\ @ B # \) ok" shows "(\ @ B # \) \ t : T" using assms proof(nominal_induct "\ @ \" t T avoiding: \ \ B rule: typing.strong_induct) case (T_Var x T) then show ?case by auto next case (T_App X t\<^sub>1 T\<^sub>2 T\<^sub>11 T\<^sub>12) then show ?case by force next case (T_Abs y T\<^sub>1 t\<^sub>2 T\<^sub>2 \ \) then have "VarB y T\<^sub>1 # \ @ \ \ t\<^sub>2 : T\<^sub>2" by simp then have closed: "T\<^sub>1 closed_in (\ @ \)" by (auto dest: typing_ok) have "\ (VarB y T\<^sub>1 # \ @ B # \) ok" by (simp add: T_Abs closed closed_in_weaken fresh_list_append fresh_list_cons fresh_trm_dom) then have "\ ((VarB y T\<^sub>1 # \) @ B # \) ok" by simp with _ have "(VarB y T\<^sub>1 # \) @ B # \ \ t\<^sub>2 : T\<^sub>2" by (rule T_Abs) simp then have "VarB y T\<^sub>1 # \ @ B # \ \ t\<^sub>2 : T\<^sub>2" by simp then show ?case by (rule typing.T_Abs) next case (T_Sub t S T \ \) from refl and \\ (\ @ B # \) ok\ have "\ @ B # \ \ t : S" by (rule T_Sub) moreover from \(\ @ \)\S<:T\ and \\ (\ @ B # \) ok\ have "(\ @ B # \)\S<:T" by (rule weakening) (simp add: extends_def T_Sub) ultimately show ?case by (rule typing.T_Sub) next case (T_TAbs X T\<^sub>1 t\<^sub>2 T\<^sub>2 \ \) from \TVarB X T\<^sub>1 # \ @ \ \ t\<^sub>2 : T\<^sub>2\ have closed: "T\<^sub>1 closed_in (\ @ \)" by (auto dest: typing_ok) have "\ (TVarB X T\<^sub>1 # \ @ B # \) ok" by (simp add: T_TAbs at_tyvrs_inst closed closed_in_weaken doms_append finite_doms finite_vrs fresh_dom fresh_fin_union fs_tyvrs_inst pt_tyvrs_inst tyvrs_fresh) then have "\ ((TVarB X T\<^sub>1 # \) @ B # \) ok" by simp with _ have "(TVarB X T\<^sub>1 # \) @ B # \ \ t\<^sub>2 : T\<^sub>2" by (rule T_TAbs) simp then have "TVarB X T\<^sub>1 # \ @ B # \ \ t\<^sub>2 : T\<^sub>2" by simp then show ?case by (rule typing.T_TAbs) next case (T_TApp X t\<^sub>1 T2 T11 T12 \ \) have "\ @ B # \ \ t\<^sub>1 : (\X<:T11. T12)" by (rule T_TApp refl)+ moreover from \(\ @ \)\T2<:T11\ and \\ (\ @ B # \) ok\ have "(\ @ B # \)\T2<:T11" by (rule weakening) (simp add: extends_def T_TApp) ultimately show ?case by (rule better_T_TApp) qed lemma type_weaken': "\ \ t : T \ \ (\@\) ok \ (\@\) \ t : T" proof (induct \) case Nil then show ?case by auto next case (Cons a \) then show ?case by (metis append_Cons append_Nil type_weaken validE(3)) qed text \A.6\ lemma strengthening: assumes "(\ @ VarB x Q # \) \ S <: T" shows "(\@\) \ S <: T" using assms proof (induct "\ @ VarB x Q # \" S T arbitrary: \) case (SA_Top S) then have "\ (\ @ \) ok" by (auto dest: valid_cons') moreover have "S closed_in (\ @ \)" using SA_Top by (auto dest: closed_in_cons) ultimately show ?case using subtype_of.SA_Top by auto next case (SA_refl_TVar X) from \\ (\ @ VarB x Q # \) ok\ have h1:"\ (\ @ \) ok" by (auto dest: valid_cons') have "X \ ty_dom (\ @ VarB x Q # \)" using SA_refl_TVar by auto then have h2:"X \ ty_dom (\ @ \)" using ty_dom_vrs by auto show ?case using h1 h2 by auto next case (SA_all T1 S1 X S2 T2) have h1:"((TVarB X T1 # \) @ \)\S2<:T2" by (fastforce intro: SA_all) have h2:"(\ @ \)\T1<:S1" using SA_all by auto then show ?case using h1 h2 by auto qed (auto) lemma narrow_type: \ \A.7\ assumes H: "\ @ (TVarB X Q) # \ \ t : T" shows "\ \ P <: Q \ \ @ (TVarB X P) # \ \ t : T" using H proof (nominal_induct "\ @ (TVarB X Q) # \" t T avoiding: P arbitrary: \ rule: typing.strong_induct) case (T_Var x T P D) then have "VarB x T \ set (D @ TVarB X P # \)" and "\ (D @ TVarB X P # \) ok" by (auto intro: replace_type dest!: subtype_implies_closed) then show ?case by auto next case (T_App t1 T1 T2 t2 P D) then show ?case by force next case (T_Abs x T1 t2 T2 P D) then show ?case by (fastforce dest: typing_ok) next case (T_Sub t S T P D) then show ?case using subtype_narrow by fastforce next case (T_TAbs X' T1 t2 T2 P D) then show ?case by (fastforce dest: typing_ok) next case (T_TApp X' t1 T2 T11 T12 P D) then have "D @ TVarB X P # \ \ t1 : Forall X' T12 T11" by fastforce moreover have "(D @ [TVarB X Q] @ \) \ T2<:T11" using T_TApp by auto then have "(D @ [TVarB X P] @ \) \ T2<:T11" using \\\P<:Q\ by (rule subtype_narrow) moreover from T_TApp have "X' \ (D @ TVarB X P # \, t1, T2)" by (simp add: fresh_list_append fresh_list_cons fresh_prod) ultimately show ?case by auto qed subsection \Substitution lemmas\ subsubsection \Substition Preserves Typing\ theorem subst_type: \ \A.8\ assumes H: "(\ @ (VarB x U) # \) \ t : T" shows "\ \ u : U \ \ @ \ \ t[x \ u] : T" using H proof (nominal_induct "\ @ (VarB x U) # \" t T avoiding: x u arbitrary: \ rule: typing.strong_induct) case (T_Var y T x u D) show ?case proof (cases "x = y") assume eq:"x=y" then have "T=U" using T_Var uniqueness_of_ctxt' by auto then show ?case using eq T_Var by (auto intro: type_weaken' dest: valid_cons') next assume "x\y" then show ?case using T_Var by (auto simp:binding.inject dest: valid_cons') qed next case (T_App t1 T1 T2 t2 x u D) then show ?case by force next case (T_Abs y T1 t2 T2 x u D) then show ?case by force next case (T_Sub t S T x u D) then have "D @ \ \ t[x \ u] : S" by auto moreover have "(D @ \) \ S<:T" using T_Sub by (auto dest: strengthening) ultimately show ?case by auto next case (T_TAbs X T1 t2 T2 x u D) from \TVarB X T1 # D @ VarB x U # \ \ t2 : T2\ have "X \ T1" by (auto simp: valid_ty_dom_fresh dest: typing_ok intro!: closed_in_fresh) with \X \ u\ and T_TAbs show ?case by fastforce next case (T_TApp X t1 T2 T11 T12 x u D) then have "(D@\) \T2<:T11" using T_TApp by (auto dest: strengthening) then show "((D @ \) \ ((t1 \\<^sub>\ T2)[x \ u]) : (T12[X \ T2]\<^sub>\))" using T_TApp by (force simp: fresh_prod fresh_list_append fresh_list_cons subst_trm_fresh_tyvar) qed subsubsection \Type Substitution Preserves Subtyping\ lemma substT_subtype: \ \A.10\ assumes H: "(\ @ ((TVarB X Q) # \)) \ S <: T" shows "\ \ P <: Q \ (\[X \ P]\<^sub>e @ \) \ S[X \ P]\<^sub>\ <: T[X \ P]\<^sub>\" using H proof (nominal_induct "\ @ TVarB X Q # \" S T avoiding: X P arbitrary: \ rule: subtype_of.strong_induct) case (SA_Top S X P D) then have "\ (D @ TVarB X Q # \) ok" by simp moreover have closed: "P closed_in \" using SA_Top subtype_implies_closed by auto ultimately have "\ (D[X \ P]\<^sub>e @ \) ok" by (rule valid_subst) moreover from SA_Top have "S closed_in (D @ TVarB X Q # \)" by simp then have "S[X \ P]\<^sub>\ closed_in (D[X \ P]\<^sub>e @ \)" using closed by (rule subst_closed_in) ultimately show ?case by auto next case (SA_trans_TVar Y S T X P D) have h:"(D @ TVarB X Q # \)\S<:T" by fact then have ST: "(D[X \ P]\<^sub>e @ \) \ S[X \ P]\<^sub>\ <: T[X \ P]\<^sub>\" using SA_trans_TVar by auto from h have G_ok: "\ (D @ TVarB X Q # \) ok" by (rule subtype_implies_ok) from G_ok and SA_trans_TVar have X_\_ok: "\ (TVarB X Q # \) ok" by (auto intro: validE_append) show "(D[X \ P]\<^sub>e @ \) \ Tvar Y[X \ P]\<^sub>\<:T[X \ P]\<^sub>\" proof (cases "X = Y") assume eq: "X = Y" from eq and SA_trans_TVar have "TVarB Y Q \ set (D @ TVarB X Q # \)" by simp with G_ok have QS: "Q = S" using \TVarB Y S \ set (D @ TVarB X Q # \)\ by (rule uniqueness_of_ctxt) from X_\_ok have "X \ ty_dom \" and "Q closed_in \" by auto then have XQ: "X \ Q" by (rule closed_in_fresh) note \\\P<:Q\ moreover from ST have "\ (D[X \ P]\<^sub>e @ \) ok" by (rule subtype_implies_ok) moreover have "(D[X \ P]\<^sub>e @ \) extends \" by (simp add: extends_def) ultimately have "(D[X \ P]\<^sub>e @ \) \ P<:Q" by (rule weakening) with QS have "(D[X \ P]\<^sub>e @ \) \ P<:S" by simp moreover from XQ and ST and QS have "(D[X \ P]\<^sub>e @ \) \ S<:T[X \ P]\<^sub>\" by (simp add: type_subst_identity) ultimately have "(D[X \ P]\<^sub>e @ \) \ P<:T[X \ P]\<^sub>\" by (rule subtype_transitivity) with eq show ?case by simp next assume neq: "X \ Y" with SA_trans_TVar have "TVarB Y S \ set D \ TVarB Y S \ set \" by (simp add: binding.inject) then show ?case proof assume "TVarB Y S \ set D" then have "TVarB Y (S[X \ P]\<^sub>\) \ set (D[X \ P]\<^sub>e)" by (rule ctxt_subst_mem_TVarB) then have "TVarB Y (S[X \ P]\<^sub>\) \ set (D[X \ P]\<^sub>e @ \)" by simp with neq and ST show ?thesis by auto next assume Y: "TVarB Y S \ set \" from X_\_ok have "X \ ty_dom \" and "\ \ ok" by auto then have "X \ \" by (simp add: valid_ty_dom_fresh) with Y have "X \ S" by (induct \) (auto simp: fresh_list_nil fresh_list_cons) with ST have "(D[X \ P]\<^sub>e @ \)\S<:T[X \ P]\<^sub>\" by (simp add: type_subst_identity) moreover from Y have "TVarB Y S \ set (D[X \ P]\<^sub>e @ \)" by simp ultimately show ?thesis using neq by auto qed qed next case (SA_refl_TVar Y X P D) note \\ (D @ TVarB X Q # \) ok\ moreover from SA_refl_TVar have closed: "P closed_in \" by (auto dest: subtype_implies_closed) ultimately have ok: "\ (D[X \ P]\<^sub>e @ \) ok" using valid_subst by auto from closed have closed': "P closed_in (D[X \ P]\<^sub>e @ \)" by (simp add: closed_in_weaken') show ?case proof (cases "X = Y") assume "X = Y" with closed' and ok show ?thesis by (auto intro: subtype_reflexivity) next assume neq: "X \ Y" with SA_refl_TVar have "Y \ ty_dom (D[X \ P]\<^sub>e @ \)" by (simp add: ty_dom_subst doms_append) with neq and ok show ?thesis by auto qed next case (SA_arrow T1 S1 S2 T2 X P D) then have h1:"(D[X \ P]\<^sub>e @ \)\T1[X \ P]\<^sub>\<:S1[X \ P]\<^sub>\" using SA_arrow by auto from SA_arrow have h2:"(D[X \ P]\<^sub>e @ \)\S2[X \ P]\<^sub>\<:T2[X \ P]\<^sub>\" using SA_arrow by auto show ?case using subtype_of.SA_arrow h1 h2 by auto next case (SA_all T1 S1 Y S2 T2 X P D) then have Y: "Y \ ty_dom (D @ TVarB X Q # \)" by (auto dest: subtype_implies_ok intro: fresh_dom) moreover from SA_all have "S1 closed_in (D @ TVarB X Q # \)" by (auto dest: subtype_implies_closed) ultimately have S1: "Y \ S1" by (rule closed_in_fresh) from SA_all have "T1 closed_in (D @ TVarB X Q # \)" by (auto dest: subtype_implies_closed) with Y have T1: "Y \ T1" by (rule closed_in_fresh) with SA_all and S1 show ?case by force qed subsubsection \Type Substitution Preserves Typing\ theorem substT_type: \ \A.11\ assumes H: "(D @ TVarB X Q # G) \ t : T" shows "G \ P <: Q \ (D[X \ P]\<^sub>e @ G) \ t[X \\<^sub>\ P] : T[X \ P]\<^sub>\" using H proof (nominal_induct "D @ TVarB X Q # G" t T avoiding: X P arbitrary: D rule: typing.strong_induct) case (T_Var x T X P D') have "G\P<:Q" by fact then have "P closed_in G" using subtype_implies_closed by auto moreover note \\ (D' @ TVarB X Q # G) ok\ ultimately have "\ (D'[X \ P]\<^sub>e @ G) ok" using valid_subst by auto moreover note \VarB x T \ set (D' @ TVarB X Q # G)\ then have "VarB x T \ set D' \ VarB x T \ set G" by simp then have "(VarB x (T[X \ P]\<^sub>\)) \ set (D'[X \ P]\<^sub>e @ G)" proof assume "VarB x T \ set D'" then have "VarB x (T[X \ P]\<^sub>\) \ set (D'[X \ P]\<^sub>e)" by (rule ctxt_subst_mem_VarB) then show ?thesis by simp next assume x: "VarB x T \ set G" from T_Var have ok: "\ G ok" by (auto dest: subtype_implies_ok) then have "X \ ty_dom G" using T_Var by (auto dest: validE_append) with ok have "X \ G" by (simp add: valid_ty_dom_fresh) moreover from x have "VarB x T \ set (D' @ G)" by simp then have "VarB x (T[X \ P]\<^sub>\) \ set ((D' @ G)[X \ P]\<^sub>e)" by (rule ctxt_subst_mem_VarB) ultimately show ?thesis by (simp add: ctxt_subst_append ctxt_subst_identity) qed ultimately show ?case by auto next case (T_App t1 T1 T2 t2 X P D') then have "D'[X \ P]\<^sub>e @ G \ t1[X \\<^sub>\ P] : (T1 \ T2)[X \ P]\<^sub>\" by auto moreover from T_App have "D'[X \ P]\<^sub>e @ G \ t2[X \\<^sub>\ P] : T1[X \ P]\<^sub>\" by auto ultimately show ?case by auto next case (T_Abs x T1 t2 T2 X P D') then show ?case by force next case (T_Sub t S T X P D') then show ?case using substT_subtype by force next case (T_TAbs X' T1 t2 T2 X P D') then have "X' \ ty_dom (D' @ TVarB X Q # G)" and "T1 closed_in (D' @ TVarB X Q # G)" by (auto dest: typing_ok) then have "X' \ T1" by (rule closed_in_fresh) with T_TAbs show ?case by force next case (T_TApp X' t1 T2 T11 T12 X P D') then have "X' \ ty_dom (D' @ TVarB X Q # G)" by (simp add: fresh_dom) moreover from T_TApp have "T11 closed_in (D' @ TVarB X Q # G)" by (auto dest: subtype_implies_closed) ultimately have X': "X' \ T11" by (rule closed_in_fresh) from T_TApp have "D'[X \ P]\<^sub>e @ G \ t1[X \\<^sub>\ P] : (\X'<:T11. T12)[X \ P]\<^sub>\" by simp with X' and T_TApp show ?case by (auto simp: fresh_atm type_substitution_lemma fresh_list_append fresh_list_cons ctxt_subst_fresh' type_subst_fresh subst_trm_ty_fresh intro: substT_subtype) qed lemma Abs_type: \ \A.13(1)\ assumes H: "\ \ (\x:S. s) : T" and H': "\ \ T <: U \ U'" and H'': "x \ \" obtains S' where "\ \ U <: S" and "(VarB x S) # \ \ s : S'" and "\ \ S' <: U'" using H H' H'' proof (nominal_induct \ t \ "\x:S. s" T avoiding: x arbitrary: U U' S s rule: typing.strong_induct) case (T_Abs y T\<^sub>1 \ t\<^sub>2 T\<^sub>2) from \\ \ T\<^sub>1 \ T\<^sub>2 <: U \ U'\ obtain ty1: "\ \ U <: S" and ty2: "\ \ T\<^sub>2 <: U'" using T_Abs by cases (simp_all add: ty.inject trm.inject alpha fresh_atm) from T_Abs have "VarB y S # \ \ [(y, x)] \ s : T\<^sub>2" by (simp add: trm.inject alpha fresh_atm) then have "[(y, x)] \ (VarB y S # \) \ [(y, x)] \ [(y, x)] \ s : [(y, x)] \ T\<^sub>2" by (rule typing.eqvt) moreover from T_Abs have "y \ \" by (auto dest!: typing_ok simp add: fresh_trm_dom) ultimately have "VarB x S # \ \ s : T\<^sub>2" using T_Abs by (perm_simp add: ty_vrs_prm_simp) with ty1 show ?case using ty2 by (rule T_Abs) next case (T_Sub \ t S T) then show ?case using subtype_transitivity by blast qed simp_all lemma subtype_reflexivity_from_typing: assumes "\ \ t : T" shows "\ \ T <: T" using assms subtype_reflexivity typing_ok typing_closed_in by simp lemma Abs_type': assumes H: "\ \ (\x:S. s) : U \ U'" and H': "x \ \" obtains S' where "\ \ U <: S" and "(VarB x S) # \ \ s : S'" and "\ \ S' <: U'" using H subtype_reflexivity_from_typing [OF H] H' by (rule Abs_type) lemma TAbs_type: \ \A.13(2)\ assumes H: "\ \ (\X<:S. s) : T" and H': "\ \ T <: (\X<:U. U')" and fresh: "X \ \" "X \ S" "X \ U" obtains S' where "\ \ U <: S" and "(TVarB X U # \) \ s : S'" and "(TVarB X U # \) \ S' <: U'" using H H' fresh proof (nominal_induct \ t \ "\X<:S. s" T avoiding: X U U' S arbitrary: s rule: typing.strong_induct) case (T_TAbs Y T\<^sub>1 \ t\<^sub>2 T\<^sub>2) from \TVarB Y T\<^sub>1 # \ \ t\<^sub>2 : T\<^sub>2\ have Y: "Y \ \" by (auto dest!: typing_ok simp add: valid_ty_dom_fresh) from \Y \ U'\ and \Y \ X\ have "(\X<:U. U') = (\Y<:U. [(Y, X)] \ U')" by (simp add: ty.inject alpha' fresh_atm) with T_TAbs have "\ \ (\Y<:S. T\<^sub>2) <: (\Y<:U. [(Y, X)] \ U')" by (simp add: trm.inject) then obtain ty1: "\ \ U <: S" and ty2: "(TVarB Y U # \) \ T\<^sub>2 <: ([(Y, X)] \ U')" using T_TAbs Y by (cases rule: subtype_of.strong_cases [where X=Y]) (simp_all add: ty.inject alpha abs_fresh) note ty1 moreover from T_TAbs have "TVarB Y S # \ \ ([(Y, X)] \ s) : T\<^sub>2" by (simp add: trm.inject alpha fresh_atm) then have "[(Y, X)] \ (TVarB Y S # \) \ [(Y, X)] \ [(Y, X)] \ s : [(Y, X)] \ T\<^sub>2" by (rule typing.eqvt) with \X \ \\ \X \ S\ Y \Y \ S\ have "TVarB X S # \ \ s : [(Y, X)] \ T\<^sub>2" by perm_simp then have "TVarB X U # \ \ s : [(Y, X)] \ T\<^sub>2" using ty1 by (rule narrow_type [of "[]", simplified]) moreover from ty2 have "([(Y, X)] \ (TVarB Y U # \)) \ ([(Y, X)] \ T\<^sub>2) <: ([(Y, X)] \ [(Y, X)] \ U')" by (rule subtype_of.eqvt) with \X \ \\ \X \ U\ Y \Y \ U\ have "(TVarB X U # \) \ ([(Y, X)] \ T\<^sub>2) <: U'" by perm_simp ultimately show ?case by (rule T_TAbs) next case (T_Sub \ t S T) then show ?case using subtype_transitivity by blast qed simp_all lemma TAbs_type': assumes H: "\ \ (\X<:S. s) : (\X<:U. U')" and fresh: "X \ \" "X \ S" "X \ U" obtains S' where "\ \ U <: S" and "(TVarB X U # \) \ s : S'" and "(TVarB X U # \) \ S' <: U'" using H subtype_reflexivity_from_typing [OF H] fresh by (rule TAbs_type) theorem preservation: \ \A.20\ assumes H: "\ \ t : T" shows "t \ t' \ \ \ t' : T" using H proof (nominal_induct avoiding: t' rule: typing.strong_induct) case (T_App \ t\<^sub>1 T\<^sub>11 T\<^sub>12 t\<^sub>2 t') obtain x::vrs where x_fresh: "x \ (\, t\<^sub>1 \ t\<^sub>2, t')" by (rule exists_fresh) (rule fin_supp) obtain X::tyvrs where "X \ (t\<^sub>1 \ t\<^sub>2, t')" by (rule exists_fresh) (rule fin_supp) with \t\<^sub>1 \ t\<^sub>2 \ t'\ show ?case proof (cases rule: eval.strong_cases [where x=x and X=X]) case (E_Abs v\<^sub>2 T\<^sub>11' t\<^sub>12) with T_App and x_fresh have h: "\ \ (\x:T\<^sub>11'. t\<^sub>12) : T\<^sub>11 \ T\<^sub>12" by (simp add: trm.inject fresh_prod) moreover from x_fresh have "x \ \" by simp ultimately obtain S' where T\<^sub>11: "\ \ T\<^sub>11 <: T\<^sub>11'" and t\<^sub>12: "(VarB x T\<^sub>11') # \ \ t\<^sub>12 : S'" and S': "\ \ S' <: T\<^sub>12" by (rule Abs_type') blast from \\ \ t\<^sub>2 : T\<^sub>11\ have "\ \ t\<^sub>2 : T\<^sub>11'" using T\<^sub>11 by (rule T_Sub) with t\<^sub>12 have "\ \ t\<^sub>12[x \ t\<^sub>2] : S'" by (rule subst_type [where \="[]", simplified]) hence "\ \ t\<^sub>12[x \ t\<^sub>2] : T\<^sub>12" using S' by (rule T_Sub) with E_Abs and x_fresh show ?thesis by (simp add: trm.inject fresh_prod) next case (E_App1 t''' t'' u) hence "t\<^sub>1 \ t''" by (simp add:trm.inject) hence "\ \ t'' : T\<^sub>11 \ T\<^sub>12" by (rule T_App) hence "\ \ t'' \ t\<^sub>2 : T\<^sub>12" using \\ \ t\<^sub>2 : T\<^sub>11\ by (rule typing.T_App) with E_App1 show ?thesis by (simp add:trm.inject) next case (E_App2 v t''' t'') hence "t\<^sub>2 \ t''" by (simp add:trm.inject) hence "\ \ t'' : T\<^sub>11" by (rule T_App) with T_App(1) have "\ \ t\<^sub>1 \ t'' : T\<^sub>12" by (rule typing.T_App) with E_App2 show ?thesis by (simp add:trm.inject) qed (simp_all add: fresh_prod) next case (T_TApp X \ t\<^sub>1 T\<^sub>2 T\<^sub>11 T\<^sub>12 t') obtain x::vrs where "x \ (t\<^sub>1 \\<^sub>\ T\<^sub>2, t')" by (rule exists_fresh) (rule fin_supp) with \t\<^sub>1 \\<^sub>\ T\<^sub>2 \ t'\ show ?case proof (cases rule: eval.strong_cases [where X=X and x=x]) case (E_TAbs T\<^sub>11' T\<^sub>2' t\<^sub>12) with T_TApp have "\ \ (\X<:T\<^sub>11'. t\<^sub>12) : (\X<:T\<^sub>11. T\<^sub>12)" and "X \ \" and "X \ T\<^sub>11'" by (simp_all add: trm.inject) moreover from \\\T\<^sub>2<:T\<^sub>11\ and \X \ \\ have "X \ T\<^sub>11" by (blast intro: closed_in_fresh fresh_dom dest: subtype_implies_closed) ultimately obtain S' where "TVarB X T\<^sub>11 # \ \ t\<^sub>12 : S'" and "(TVarB X T\<^sub>11 # \) \ S' <: T\<^sub>12" by (rule TAbs_type') blast hence "TVarB X T\<^sub>11 # \ \ t\<^sub>12 : T\<^sub>12" by (rule T_Sub) hence "\ \ t\<^sub>12[X \\<^sub>\ T\<^sub>2] : T\<^sub>12[X \ T\<^sub>2]\<^sub>\" using \\ \ T\<^sub>2 <: T\<^sub>11\ by (rule substT_type [where D="[]", simplified]) with T_TApp and E_TAbs show ?thesis by (simp add: trm.inject) next case (E_TApp t''' t'' T) from E_TApp have "t\<^sub>1 \ t''" by (simp add: trm.inject) then have "\ \ t'' : (\X<:T\<^sub>11. T\<^sub>12)" by (rule T_TApp) then have "\ \ t'' \\<^sub>\ T\<^sub>2 : T\<^sub>12[X \ T\<^sub>2]\<^sub>\" using \\ \ T\<^sub>2 <: T\<^sub>11\ by (rule better_T_TApp) with E_TApp show ?thesis by (simp add: trm.inject) qed (simp_all add: fresh_prod) next case (T_Sub \ t S T t') have "t \ t'" by fact hence "\ \ t' : S" by (rule T_Sub) moreover have "\ \ S <: T" by fact ultimately show ?case by (rule typing.T_Sub) qed (auto) lemma Fun_canonical: \ \A.14(1)\ assumes ty: "[] \ v : T\<^sub>1 \ T\<^sub>2" shows "val v \ \x t S. v = (\x:S. t)" using ty proof (induct "[]::env" v "T\<^sub>1 \ T\<^sub>2" arbitrary: T\<^sub>1 T\<^sub>2) case (T_Sub t S) from \[] \ S <: T\<^sub>1 \ T\<^sub>2\ obtain S\<^sub>1 S\<^sub>2 where S: "S = S\<^sub>1 \ S\<^sub>2" by cases (auto simp: T_Sub) then show ?case using \val t\ by (rule T_Sub) qed (auto) lemma TyAll_canonical: \ \A.14(3)\ fixes X::tyvrs assumes ty: "[] \ v : (\X<:T\<^sub>1. T\<^sub>2)" shows "val v \ \X t S. v = (\X<:S. t)" using ty proof (induct "[]::env" v "\X<:T\<^sub>1. T\<^sub>2" arbitrary: X T\<^sub>1 T\<^sub>2) case (T_Sub t S) from \[] \ S <: (\X<:T\<^sub>1. T\<^sub>2)\ obtain X S\<^sub>1 S\<^sub>2 where S: "S = (\X<:S\<^sub>1. S\<^sub>2)" by cases (auto simp: T_Sub) then show ?case using T_Sub by auto qed (auto) theorem progress: assumes "[] \ t : T" shows "val t \ (\t'. t \ t')" using assms proof (induct "[]::env" t T) case (T_App t\<^sub>1 T\<^sub>11 T\<^sub>12 t\<^sub>2) hence "val t\<^sub>1 \ (\t'. t\<^sub>1 \ t')" by simp thus ?case proof assume t\<^sub>1_val: "val t\<^sub>1" with T_App obtain x t3 S where t\<^sub>1: "t\<^sub>1 = (\x:S. t3)" by (auto dest!: Fun_canonical) from T_App have "val t\<^sub>2 \ (\t'. t\<^sub>2 \ t')" by simp thus ?case proof assume "val t\<^sub>2" with t\<^sub>1 have "t\<^sub>1 \ t\<^sub>2 \ t3[x \ t\<^sub>2]" by auto thus ?case by auto next assume "\t'. t\<^sub>2 \ t'" then obtain t' where "t\<^sub>2 \ t'" by auto with t\<^sub>1_val have "t\<^sub>1 \ t\<^sub>2 \ t\<^sub>1 \ t'" by auto thus ?case by auto qed next assume "\t'. t\<^sub>1 \ t'" then obtain t' where "t\<^sub>1 \ t'" by auto hence "t\<^sub>1 \ t\<^sub>2 \ t' \ t\<^sub>2" by auto thus ?case by auto qed next case (T_TApp X t\<^sub>1 T\<^sub>2 T\<^sub>11 T\<^sub>12) hence "val t\<^sub>1 \ (\t'. t\<^sub>1 \ t')" by simp thus ?case proof assume "val t\<^sub>1" with T_TApp obtain x t S where "t\<^sub>1 = (\x<:S. t)" by (auto dest!: TyAll_canonical) hence "t\<^sub>1 \\<^sub>\ T\<^sub>2 \ t[x \\<^sub>\ T\<^sub>2]" by auto thus ?case by auto next assume "\t'. t\<^sub>1 \ t'" thus ?case by auto qed qed (auto) end diff --git a/src/HOL/Nominal/Examples/Lam_Funs.thy b/src/HOL/Nominal/Examples/Lam_Funs.thy --- a/src/HOL/Nominal/Examples/Lam_Funs.thy +++ b/src/HOL/Nominal/Examples/Lam_Funs.thy @@ -1,152 +1,149 @@ theory Lam_Funs imports "HOL-Nominal.Nominal" begin text \ Provides useful definitions for reasoning with lambda-terms. \ atom_decl name nominal_datatype lam = Var "name" | App "lam" "lam" | Lam "\name\lam" ("Lam [_]._" [100,100] 100) text \The depth of a lambda-term.\ nominal_primrec depth :: "lam \ nat" where "depth (Var x) = 1" | "depth (App t1 t2) = (max (depth t1) (depth t2)) + 1" | "depth (Lam [a].t) = (depth t) + 1" - apply(finite_guess)+ - apply(rule TrueI)+ - apply(simp add: fresh_nat) - apply(fresh_guess)+ - done + by(finite_guess | simp | fresh_guess)+ text \ The free variables of a lambda-term. A complication in this function arises from the fact that it returns a name set, which is not a finitely supported type. Therefore we have to prove the invariant that frees always returns a finite set of names. \ nominal_primrec (invariant: "\s::name set. finite s") frees :: "lam \ name set" where "frees (Var a) = {a}" | "frees (App t1 t2) = (frees t1) \ (frees t2)" | "frees (Lam [a].t) = (frees t) - {a}" -apply(finite_guess)+ -apply(simp)+ -apply(simp add: fresh_def) -apply(simp add: supp_of_fin_sets[OF pt_name_inst, OF at_name_inst, OF fs_at_inst[OF at_name_inst]]) -apply(simp add: supp_atm) -apply(blast) +apply(finite_guess | simp add: fresh_def | fresh_guess)+ + apply (simp add: at_fin_set_supp at_name_inst) apply(fresh_guess)+ done text \ We can avoid the definition of frees by using the build in notion of support. \ lemma frees_equals_support: shows "frees t = supp t" by (nominal_induct t rule: lam.strong_induct) (simp_all add: lam.supp supp_atm abs_supp) text \Parallel and single capture-avoiding substitution.\ fun lookup :: "(name\lam) list \ name \ lam" where "lookup [] x = Var x" | "lookup ((y,e)#\) x = (if x=y then e else lookup \ x)" lemma lookup_eqvt[eqvt]: fixes pi::"name prm" and \::"(name\lam) list" and X::"name" shows "pi\(lookup \ X) = lookup (pi\\) (pi\X)" by (induct \) (auto simp add: eqvts) nominal_primrec psubst :: "(name\lam) list \ lam \ lam" ("_<_>" [95,95] 105) where "\<(Var x)> = (lookup \ x)" | "\<(App e\<^sub>1 e\<^sub>2)> = App (\1>) (\2>)" | "x\\ \ \<(Lam [x].e)> = Lam [x].(\)" -apply(finite_guess)+ -apply(rule TrueI)+ -apply(simp add: abs_fresh)+ -apply(fresh_guess)+ -done + by (finite_guess | simp add: abs_fresh | fresh_guess)+ lemma psubst_eqvt[eqvt]: fixes pi::"name prm" and t::"lam" shows "pi\(\) = (pi\\)<(pi\t)>" by (nominal_induct t avoiding: \ rule: lam.strong_induct) (simp_all add: eqvts fresh_bij) abbreviation subst :: "lam \ name \ lam \ lam" ("_[_::=_]" [100,100,100] 100) where "t[x::=t'] \ ([(x,t')])" lemma subst[simp]: shows "(Var x)[y::=t'] = (if x=y then t' else (Var x))" and "(App t1 t2)[y::=t'] = App (t1[y::=t']) (t2[y::=t'])" and "x\(y,t') \ (Lam [x].t)[y::=t'] = Lam [x].(t[y::=t'])" by (simp_all add: fresh_list_cons fresh_list_nil) lemma subst_supp: shows "supp(t1[a::=t2]) \ (((supp(t1)-{a})\supp(t2))::name set)" -apply(nominal_induct t1 avoiding: a t2 rule: lam.strong_induct) -apply(auto simp add: lam.supp supp_atm fresh_prod abs_supp) -apply(blast)+ -done +proof (nominal_induct t1 avoiding: a t2 rule: lam.strong_induct) + case (Var name) + then show ?case + by (simp add: lam.supp(1) supp_atm) +next + case (App lam1 lam2) + then show ?case + using lam.supp(2) by fastforce +next + case (Lam name lam) + then show ?case + using frees.simps(3) frees_equals_support by auto +qed text \ Contexts - lambda-terms with a single hole. Note that the lambda case in contexts does not bind a name, even if we introduce the notation [_]._ for CLam. \ nominal_datatype clam = Hole ("\" 1000) | CAppL "clam" "lam" | CAppR "lam" "clam" | CLam "name" "clam" ("CLam [_]._" [100,100] 100) text \Filling a lambda-term into a context.\ nominal_primrec filling :: "clam \ lam \ lam" ("_\_\" [100,100] 100) where "\\t\ = t" | "(CAppL E t')\t\ = App (E\t\) t'" | "(CAppR t' E)\t\ = App t' (E\t\)" | "(CLam [x].E)\t\ = Lam [x].(E\t\)" by (rule TrueI)+ text \Composition od two contexts\ nominal_primrec clam_compose :: "clam \ clam \ clam" ("_ \ _" [100,100] 100) where "\ \ E' = E'" | "(CAppL E t') \ E' = CAppL (E \ E') t'" | "(CAppR t' E) \ E' = CAppR t' (E \ E')" | "(CLam [x].E) \ E' = CLam [x].(E \ E')" by (rule TrueI)+ lemma clam_compose: shows "(E1 \ E2)\t\ = E1\E2\t\\" by (induct E1 rule: clam.induct) (auto) end diff --git a/src/HOL/Nominal/Examples/W.thy b/src/HOL/Nominal/Examples/W.thy --- a/src/HOL/Nominal/Examples/W.thy +++ b/src/HOL/Nominal/Examples/W.thy @@ -1,632 +1,632 @@ theory W imports "HOL-Nominal.Nominal" begin text \Example for strong induction rules avoiding sets of atoms.\ atom_decl tvar var abbreviation "difference_list" :: "'a list \ 'a list \ 'a list" ("_ - _" [60,60] 60) where "xs - ys \ [x \ xs. x\set ys]" lemma difference_eqvt_tvar[eqvt]: fixes pi::"tvar prm" and Xs Ys::"tvar list" shows "pi\(Xs - Ys) = (pi\Xs) - (pi\Ys)" by (induct Xs) (simp_all add: eqvts) lemma difference_fresh [simp]: fixes X::"tvar" and Xs Ys::"tvar list" shows "X\(Xs - Ys) \ X\Xs \ X\set Ys" by (induct Xs) (auto simp add: fresh_list_nil fresh_list_cons fresh_atm) lemma difference_supset: fixes xs::"'a list" and ys::"'a list" and zs::"'a list" assumes asm: "set xs \ set ys" shows "xs - ys = []" using asm by (induct xs) (auto) nominal_datatype ty = TVar "tvar" | Fun "ty" "ty" ("_\_" [100,100] 100) nominal_datatype tyS = Ty "ty" | ALL "\tvar\tyS" ("\[_]._" [100,100] 100) nominal_datatype trm = Var "var" | App "trm" "trm" | Lam "\var\trm" ("Lam [_]._" [100,100] 100) | Let "\var\trm" "trm" abbreviation LetBe :: "var \ trm \ trm \ trm" ("Let _ be _ in _" [100,100,100] 100) where "Let x be t1 in t2 \ trm.Let x t2 t1" type_synonym Ctxt = "(var\tyS) list" text \free type variables\ consts ftv :: "'a \ tvar list" overloading ftv_prod \ "ftv :: ('a \ 'b) \ tvar list" ftv_tvar \ "ftv :: tvar \ tvar list" ftv_var \ "ftv :: var \ tvar list" ftv_list \ "ftv :: 'a list \ tvar list" ftv_ty \ "ftv :: ty \ tvar list" begin primrec ftv_prod where "ftv_prod (x, y) = (ftv x) @ (ftv y)" definition ftv_tvar :: "tvar \ tvar list" where [simp]: "ftv_tvar X \ [(X::tvar)]" definition ftv_var :: "var \ tvar list" where [simp]: "ftv_var x \ []" primrec ftv_list where "ftv_list [] = []" | "ftv_list (x#xs) = (ftv x)@(ftv_list xs)" nominal_primrec ftv_ty :: "ty \ tvar list" where "ftv_ty (TVar X) = [X]" | "ftv_ty (T1 \T2) = (ftv_ty T1) @ (ftv_ty T2)" by (rule TrueI)+ end lemma ftv_ty_eqvt[eqvt]: fixes pi::"tvar prm" and T::"ty" shows "pi\(ftv T) = ftv (pi\T)" by (nominal_induct T rule: ty.strong_induct) (perm_simp add: append_eqvt)+ overloading ftv_tyS \ "ftv :: tyS \ tvar list" begin nominal_primrec ftv_tyS :: "tyS \ tvar list" where "ftv_tyS (Ty T) = ((ftv (T::ty))::tvar list)" | "ftv_tyS (\[X].S) = (ftv_tyS S) - [X]" apply(finite_guess add: ftv_ty_eqvt fs_tvar1 | rule TrueI)+ apply (metis difference_fresh list.set_intros(1)) apply(fresh_guess add: ftv_ty_eqvt fs_tvar1)+ done end lemma ftv_tyS_eqvt[eqvt]: fixes pi::"tvar prm" and S::"tyS" shows "pi\(ftv S) = ftv (pi\S)" proof (nominal_induct S rule: tyS.strong_induct) case (Ty ty) then show ?case by (simp add: ftv_ty_eqvt) next case (ALL tvar tyS) then show ?case by (metis difference_eqvt_tvar ftv_ty.simps(1) ftv_tyS.simps(2) ftv_ty_eqvt ty.perm(3) tyS.perm(4)) qed lemma ftv_Ctxt_eqvt[eqvt]: fixes pi::"tvar prm" and \::"Ctxt" shows "pi\(ftv \) = ftv (pi\\)" by (induct \) (auto simp add: eqvts) text \Valid\ inductive valid :: "Ctxt \ bool" where V_Nil[intro]: "valid []" | V_Cons[intro]: "\valid \;x\\\\ valid ((x,S)#\)" equivariance valid text \General\ primrec gen :: "ty \ tvar list \ tyS" where "gen T [] = Ty T" | "gen T (X#Xs) = \[X].(gen T Xs)" lemma gen_eqvt[eqvt]: fixes pi::"tvar prm" shows "pi\(gen T Xs) = gen (pi\T) (pi\Xs)" by (induct Xs) (simp_all add: eqvts) abbreviation close :: "Ctxt \ ty \ tyS" where "close \ T \ gen T ((ftv T) - (ftv \))" lemma close_eqvt[eqvt]: fixes pi::"tvar prm" shows "pi\(close \ T) = close (pi\\) (pi\T)" by (simp_all only: eqvts) text \Substitution\ type_synonym Subst = "(tvar\ty) list" consts psubst :: "Subst \ 'a \ 'a" ("_<_>" [100,60] 120) abbreviation subst :: "'a \ tvar \ ty \ 'a" ("_[_::=_]" [100,100,100] 100) where "smth[X::=T] \ ([(X,T)])" fun lookup :: "Subst \ tvar \ ty" where "lookup [] X = TVar X" | "lookup ((Y,T)#\) X = (if X=Y then T else lookup \ X)" lemma lookup_eqvt[eqvt]: fixes pi::"tvar prm" shows "pi\(lookup \ X) = lookup (pi\\) (pi\X)" by (induct \) (auto simp add: eqvts) lemma lookup_fresh: fixes X::"tvar" assumes a: "X\\" shows "lookup \ X = TVar X" using a by (induct \) (auto simp add: fresh_list_cons fresh_prod fresh_atm) overloading psubst_ty \ "psubst :: Subst \ ty \ ty" begin nominal_primrec psubst_ty where "\ = lookup \ X" | "\1 \ T\<^sub>2> = (\1>) \ (\2>)" by (rule TrueI)+ end lemma psubst_ty_eqvt[eqvt]: fixes pi::"tvar prm" and \::"Subst" and T::"ty" shows "pi\(\) = (pi\\)<(pi\T)>" by (induct T rule: ty.induct) (simp_all add: eqvts) overloading psubst_tyS \ "psubst :: Subst \ tyS \ tyS" begin nominal_primrec psubst_tyS :: "Subst \ tyS \ tyS" where "\<(Ty T)> = Ty (\)" | "X\\ \ \<(\[X].S)> = \[X].(\)" apply(finite_guess add: psubst_ty_eqvt fs_tvar1 | simp add: abs_fresh)+ apply(fresh_guess add: psubst_ty_eqvt fs_tvar1)+ done end overloading psubst_Ctxt \ "psubst :: Subst \ Ctxt \ Ctxt" begin fun psubst_Ctxt :: "Subst \ Ctxt \ Ctxt" where "psubst_Ctxt \ [] = []" | "psubst_Ctxt \ ((x,S)#\) = (x,\)#(psubst_Ctxt \ \)" end lemma fresh_lookup: fixes X::"tvar" and \::"Subst" and Y::"tvar" assumes asms: "X\Y" "X\\" shows "X\(lookup \ Y)" using asms by (induct \) (auto simp add: fresh_list_cons fresh_prod fresh_atm) lemma fresh_psubst_ty: fixes X::"tvar" and \::"Subst" and T::"ty" assumes asms: "X\\" "X\T" shows "X\\" using asms by (nominal_induct T rule: ty.strong_induct) (auto simp add: fresh_list_append fresh_list_cons fresh_prod fresh_lookup) lemma fresh_psubst_tyS: fixes X::"tvar" and \::"Subst" and S::"tyS" assumes asms: "X\\" "X\S" shows "X\\" using asms by (nominal_induct S avoiding: \ X rule: tyS.strong_induct) (auto simp add: fresh_psubst_ty abs_fresh) lemma fresh_psubst_Ctxt: fixes X::"tvar" and \::"Subst" and \::"Ctxt" assumes asms: "X\\" "X\\" shows "X\\<\>" using asms by (induct \) (auto simp add: fresh_psubst_tyS fresh_list_cons) lemma subst_freshfact2_ty: fixes X::"tvar" and Y::"tvar" and T::"ty" assumes asms: "X\S" shows "X\T[X::=S]" using asms by (nominal_induct T rule: ty.strong_induct) (auto simp add: fresh_atm) text \instance of a type scheme\ inductive inst :: "ty \ tyS \ bool"("_ \ _" [50,51] 50) where I_Ty[intro]: "T \ (Ty T)" | I_All[intro]: "\X\T'; T \ S\ \ T[X::=T'] \ \[X].S" equivariance inst[tvar] nominal_inductive inst by (simp_all add: abs_fresh subst_freshfact2_ty) lemma subst_forget_ty: fixes T::"ty" and X::"tvar" assumes a: "X\T" shows "T[X::=S] = T" using a by (nominal_induct T rule: ty.strong_induct) (auto simp add: fresh_atm) lemma psubst_ty_lemma: fixes \::"Subst" and X::"tvar" and T'::"ty" and T::"ty" assumes a: "X\\" shows "\ = (\)[X::=\]" using a proof (nominal_induct T avoiding: \ X T' rule: ty.strong_induct) case (TVar tvar) then show ?case by (simp add: fresh_atm(1) fresh_lookup lookup_fresh subst_forget_ty) qed auto lemma general_preserved: fixes \::"Subst" assumes a: "T \ S" shows "\ \ \" using a proof (nominal_induct T S avoiding: \ rule: inst.strong_induct) case (I_Ty T) then show ?case by (simp add: inst.I_Ty) next case (I_All X T' T S) then show ?case by (simp add: fresh_psubst_ty inst.I_All psubst_ty_lemma) qed text\typing judgements\ inductive typing :: "Ctxt \ trm \ ty \ bool" (" _ \ _ : _ " [60,60,60] 60) where T_VAR[intro]: "\valid \; (x,S)\set \; T \ S\\ \ \ Var x : T" | T_APP[intro]: "\\ \ t\<^sub>1 : T\<^sub>1\T\<^sub>2; \ \ t\<^sub>2 : T\<^sub>1\\ \ \ App t\<^sub>1 t\<^sub>2 : T\<^sub>2" | T_LAM[intro]: "\x\\;((x,Ty T\<^sub>1)#\) \ t : T\<^sub>2\ \ \ \ Lam [x].t : T\<^sub>1\T\<^sub>2" | T_LET[intro]: "\x\\; \ \ t\<^sub>1 : T\<^sub>1; ((x,close \ T\<^sub>1)#\) \ t\<^sub>2 : T\<^sub>2; set (ftv T\<^sub>1 - ftv \) \* T\<^sub>2\ \ \ \ Let x be t\<^sub>1 in t\<^sub>2 : T\<^sub>2" equivariance typing[tvar] lemma fresh_tvar_trm: fixes X::"tvar" and t::"trm" shows "X\t" by (nominal_induct t rule: trm.strong_induct) (simp_all add: fresh_atm abs_fresh) lemma ftv_ty: fixes T::"ty" shows "supp T = set (ftv T)" by (nominal_induct T rule: ty.strong_induct) (simp_all add: ty.supp supp_atm) lemma ftv_tyS: fixes S::"tyS" shows "supp S = set (ftv S)" by (nominal_induct S rule: tyS.strong_induct) (auto simp add: tyS.supp abs_supp ftv_ty) lemma ftv_Ctxt: fixes \::"Ctxt" shows "supp \ = set (ftv \)" proof (induct \) case Nil then show ?case by (simp add: supp_list_nil) next case (Cons c \) show ?case proof (cases c) case (Pair a b) with Cons show ?thesis by (simp add: ftv_tyS supp_atm(3) supp_list_cons supp_prod) qed qed lemma ftv_tvars: fixes Tvs::"tvar list" shows "supp Tvs = set Tvs" by (induct Tvs) (simp_all add: supp_list_nil supp_list_cons supp_atm) lemma difference_supp: fixes xs ys::"tvar list" shows "((supp (xs - ys))::tvar set) = supp xs - supp ys" by (induct xs) (auto simp add: supp_list_nil supp_list_cons ftv_tvars) lemma set_supp_eq: fixes xs::"tvar list" shows "set xs = supp xs" by (induct xs) (simp_all add: supp_list_nil supp_list_cons supp_atm) nominal_inductive2 typing avoids T_LET: "set (ftv T\<^sub>1 - ftv \)" apply (simp_all add: fresh_star_def fresh_def ftv_Ctxt fresh_tvar_trm) by (meson fresh_def fresh_tvar_trm) lemma perm_fresh_fresh_aux: "\(x,y)\set (pi::tvar prm). x \ z \ y \ z \ pi \ (z::'a::pt_tvar) = z" proof (induct pi rule: rev_induct) case Nil then show ?case by simp next case (snoc x xs) then show ?case - apply (simp add: split_paired_all pt_tvar2) + unfolding split_paired_all pt_tvar2 using perm_fresh_fresh(1) by fastforce qed lemma freshs_mem: fixes S::"tvar set" assumes "x \ S" and "S \* z" shows "x \ z" using assms by (simp add: fresh_star_def) lemma fresh_gen_set: fixes X::"tvar" and Xs::"tvar list" assumes "X\set Xs" shows "X\gen T Xs" using assms by (induct Xs) (auto simp: abs_fresh) lemma close_fresh: fixes \::"Ctxt" shows "\(X::tvar)\set ((ftv T) - (ftv \)). X\(close \ T)" by (meson fresh_gen_set) lemma gen_supp: shows "(supp (gen T Xs)::tvar set) = supp T - supp Xs" by (induct Xs) (auto simp add: supp_list_nil supp_list_cons tyS.supp abs_supp supp_atm) lemma minus_Int_eq: shows "T - (T - U) = T \ U" by blast lemma close_supp: shows "supp (close \ T) = set (ftv T) \ set (ftv \)" using difference_supp ftv_ty gen_supp set_supp_eq by auto lemma better_T_LET: assumes x: "x\\" and t1: "\ \ t\<^sub>1 : T\<^sub>1" and t2: "((x,close \ T\<^sub>1)#\) \ t\<^sub>2 : T\<^sub>2" shows "\ \ Let x be t\<^sub>1 in t\<^sub>2 : T\<^sub>2" proof - have fin: "finite (set (ftv T\<^sub>1 - ftv \))" by simp obtain pi where pi1: "(pi \ set (ftv T\<^sub>1 - ftv \)) \* (T\<^sub>2, \)" and pi2: "set pi \ set (ftv T\<^sub>1 - ftv \) \ (pi \ set (ftv T\<^sub>1 - ftv \))" by (rule at_set_avoiding [OF at_tvar_inst fin fs_tvar1, of "(T\<^sub>2, \)"]) from pi1 have pi1': "(pi \ set (ftv T\<^sub>1 - ftv \)) \* \" by (simp add: fresh_star_prod) have Gamma_fresh: "\(x,y)\set pi. x \ \ \ y \ \" using freshs_mem [OF _ pi1'] subsetD [OF pi2] ftv_Ctxt fresh_def by fastforce have "\x y. \x \ set (ftv T\<^sub>1 - ftv \); y \ pi \ set (ftv T\<^sub>1 - ftv \)\ \ x \ close \ T\<^sub>1 \ y \ close \ T\<^sub>1" by (metis DiffE filter_set fresh_def fresh_gen_set freshs_mem ftv_Ctxt ftv_ty gen_supp member_filter pi1') then have close_fresh': "\(x, y)\set pi. x \ close \ T\<^sub>1 \ y \ close \ T\<^sub>1" using pi2 by auto note x moreover from Gamma_fresh perm_boolI [OF t1, of pi] have "\ \ t\<^sub>1 : pi \ T\<^sub>1" by (simp add: perm_fresh_fresh_aux eqvts fresh_tvar_trm) moreover from t2 close_fresh' have "(x,(pi \ close \ T\<^sub>1))#\ \ t\<^sub>2 : T\<^sub>2" by (simp add: perm_fresh_fresh_aux) with Gamma_fresh have "(x,close \ (pi \ T\<^sub>1))#\ \ t\<^sub>2 : T\<^sub>2" by (simp add: close_eqvt perm_fresh_fresh_aux) moreover from pi1 Gamma_fresh have "set (ftv (pi \ T\<^sub>1) - ftv \) \* T\<^sub>2" by (simp only: eqvts fresh_star_prod perm_fresh_fresh_aux) ultimately show ?thesis by (rule T_LET) qed lemma ftv_ty_subst: fixes T::"ty" and \::"Subst" and X Y ::"tvar" assumes "X \ set (ftv T)" and "Y \ set (ftv (lookup \ X))" shows "Y \ set (ftv (\))" using assms by (nominal_induct T rule: ty.strong_induct) (auto) lemma ftv_tyS_subst: fixes S::"tyS" and \::"Subst" and X Y::"tvar" assumes "X \ set (ftv S)" and "Y \ set (ftv (lookup \ X))" shows "Y \ set (ftv (\))" using assms by (nominal_induct S avoiding: \ Y rule: tyS.strong_induct) (auto simp add: ftv_ty_subst fresh_atm) lemma ftv_Ctxt_subst: fixes \::"Ctxt" and \::"Subst" assumes "X \ set (ftv \)" and "Y \ set (ftv (lookup \ X))" shows "Y \ set (ftv (\<\>))" using assms by (induct \) (auto simp add: ftv_tyS_subst) lemma gen_preserved1: assumes "Xs \* \" shows "\ = gen (\) Xs" using assms by (induct Xs) (auto simp add: fresh_star_def) lemma gen_preserved2: fixes T::"ty" and \::"Ctxt" assumes "((ftv T) - (ftv \)) \* \" shows "((ftv (\)) - (ftv (\<\>))) = ((ftv T) - (ftv \))" using assms proof(nominal_induct T rule: ty.strong_induct) case (TVar tvar) - then show ?case + then show ?case apply(auto simp add: fresh_star_def ftv_Ctxt_subst) by (metis filter.simps fresh_def fresh_psubst_Ctxt ftv_Ctxt ftv_ty.simps(1) lookup_fresh) next case (Fun ty1 ty2) then show ?case by (simp add: fresh_star_list) qed lemma close_preserved: fixes \::"Ctxt" assumes "((ftv T) - (ftv \)) \* \" shows "\ T> = close (\<\>) (\)" using assms by (simp add: gen_preserved1 gen_preserved2) lemma var_fresh_for_ty: fixes x::"var" and T::"ty" shows "x\T" by (nominal_induct T rule: ty.strong_induct) (simp_all add: fresh_atm) lemma var_fresh_for_tyS: fixes x::"var" and S::"tyS" shows "x\S" by (nominal_induct S rule: tyS.strong_induct) (simp_all add: abs_fresh var_fresh_for_ty) lemma psubst_fresh_Ctxt: fixes x::"var" and \::"Ctxt" and \::"Subst" shows "x\\<\> = x\\" by (induct \) (auto simp add: fresh_list_cons fresh_list_nil fresh_prod var_fresh_for_tyS) lemma psubst_valid: fixes \::Subst and \::Ctxt assumes "valid \" shows "valid (\<\>)" using assms by (induct) (auto simp add: psubst_fresh_Ctxt) lemma psubst_in: fixes \::"Ctxt" and \::"Subst" and pi::"tvar prm" and S::"tyS" assumes a: "(x,S)\set \" shows "(x,\)\set (\<\>)" using a by (induct \) (auto simp add: calc_atm) lemma typing_preserved: fixes \::"Subst" and pi::"tvar prm" assumes "\ \ t : T" shows "(\<\>) \ t : (\)" using assms proof (nominal_induct \ t T avoiding: \ rule: typing.strong_induct) case (T_VAR \ x S T) have a1: "valid \" by fact have a2: "(x, S) \ set \" by fact have a3: "T \ S" by fact have "valid (\<\>)" using a1 by (simp add: psubst_valid) moreover have "(x,\)\set (\<\>)" using a2 by (simp add: psubst_in) moreover have "\ \ \" using a3 by (simp add: general_preserved) ultimately show "(\<\>) \ Var x : (\)" by (simp add: typing.T_VAR) next case (T_APP \ t1 T1 T2 t2) have "\<\> \ t1 : \ T2>" by fact then have "\<\> \ t1 : (\) \ (\)" by simp moreover have "\<\> \ t2 : \" by fact ultimately show "\<\> \ App t1 t2 : \" by (simp add: typing.T_APP) next case (T_LAM x \ T1 t T2) fix pi::"tvar prm" and \::"Subst" have "x\\" by fact then have "x\\<\>" by (simp add: psubst_fresh_Ctxt) moreover have "\<((x, Ty T1)#\)> \ t : \" by fact then have "((x, Ty (\))#(\<\>)) \ t : \" by (simp add: calc_atm) ultimately show "\<\> \ Lam [x].t : \ T2>" by (simp add: typing.T_LAM) next case (T_LET x \ t1 T1 t2 T2) have vc: "((ftv T1) - (ftv \)) \* \" by fact have "x\\" by fact then have a1: "x\\<\>" by (simp add: calc_atm psubst_fresh_Ctxt) have a2: "\<\> \ t1 : \" by fact have a3: "\<((x, close \ T1)#\)> \ t2 : \" by fact from a2 a3 show "\<\> \ Let x be t1 in t2 : \" by (simp add: a1 better_T_LET close_preserved vc) qed end