header {* Hand-in on 10 June at noon. Please rename the file and send your solution to me as Hw13_\your name\ The purpose of this homework is to prove the type-preservation property for beta-reduction. *} theory Hw13 imports Nominal begin text {* Lambda-terms and substitution *} atom_decl name nominal_datatype lam = Var "name" | App "lam" "lam" | Lam "\name\lam" ("Lam [_]._") consts subst :: "lam \ name \ lam \ lam" ("_[_::=_]" [100,100,100] 100) nominal_primrec "(Var x)[y::=s] = (if x=y then s else (Var x))" "(App t\<^isub>1 t\<^isub>2)[y::=s] = App (t\<^isub>1[y::=s]) (t\<^isub>2[y::=s])" "x\(y,s) \ (Lam [x].t)[y::=s] = Lam [x].(t[y::=s])" apply(finite_guess)+ apply(rule TrueI)+ apply(simp add: abs_fresh) apply(fresh_guess)+ done lemma subst_eqvt[eqvt]: fixes pi::"name prm" shows "pi\(t1[x::=t2]) = (pi\t1)[(pi\x)::=(pi\t2)]" by (nominal_induct t1 avoiding: x t2 rule: lam.strong_induct) (auto simp add: perm_bij fresh_atm fresh_bij) text {* Task 1 (easy) Later on we need the following fact about how freshness behaves in substitutions. Prove this lemma by structural induction on t where you have to avoid z, y and s. To set up the induction you have to use nominal_induct and the rule lam.induct. *} lemma fresh_fact: fixes z::"name" shows "\z\s; (z=y \ z\t)\ \ z\t[y::=s]" by (nominal_induct t avoiding: z y s rule: lam.strong_induct) (auto simp add: abs_fresh fresh_prod fresh_atm) text {* Types *} nominal_datatype ty = TVar "string" | TArr "ty" "ty" ("_ \ _") lemma ty_fresh: fixes x::"name" and T::"ty" shows "x\T" by (induct T rule: ty.induct) (auto simp add: fresh_string) text {* Sublists and context difference *} abbreviation "sub_list" :: "(name\ty) list\(name\ty) list\bool" ("_ \ _") where "\\<^isub>1 \ \\<^isub>2 \ \x T. (x,T) \ set \\<^isub>1 \ (x,T) \ set \\<^isub>2" abbreviation "diff_list" :: "'a list \ 'a list \ 'a list" ("_ - _") where "xs - ys \ [x \ xs. x\set ys]" lemma diff_cons[simp]: assumes a: "x\set ys" shows "(x#xs)-ys = x#(xs-ys)" using a by auto text {* Task 2 (easy) We also need the fact how freshness behaves when we remove some members of a list. Prove the following lemma by induction on \. The lemmas thm fresh_list_nil fresh_list_cons might be helpful. *} lemma fresh_diff: fixes x::"name" and \ \::"(name\ty) list" assumes a: "x\\" shows "x\(\-\)" using a by (induct \) (auto simp add: fresh_list_cons) text {* Validity of typing contexts *} inductive valid :: "(name\ty) list \ bool" where v1[intro]: "valid []" | v2[intro]: "\valid \; x\\\\ valid ((x,T)#\)" equivariance valid lemma valid_elim: assumes a: "valid ((x,T)#\)" shows "x\\ \ valid \" using a by (cases) (auto) lemma valid_diff: assumes a: "valid \" shows "valid (\-\)" using a by (induct) (auto simp add: fresh_diff) lemma fresh_set: shows "y\xs = (\x\set xs. y\x)" by (induct xs) (simp_all add: fresh_list_nil fresh_list_cons) lemma context_unique: assumes a1: "valid \" and a2: "(x,T) \ set \" and a3: "(x,U) \ set \" shows "T = U" using a1 a2 a3 by (induct) (auto simp add: fresh_set fresh_prod fresh_atm) text {* The typing relation *} inductive typing :: "(name\ty) list\lam\ty\bool" ("_ \ _ : _") where t1[intro]: "\valid \; (x,T)\set \\ \ \ \ Var x : T" | t2[intro]: "\\ \ t\<^isub>1 : T\<^isub>1\T\<^isub>2; \ \ t\<^isub>2 : T\<^isub>1\ \ \ \ App t\<^isub>1 t\<^isub>2 : T\<^isub>2" | t3[intro]: "\x\\; (x,T\<^isub>1)#\ \ t : T\<^isub>2\ \ \ \ Lam [x].t : T\<^isub>1\T\<^isub>2" equivariance typing nominal_inductive typing by (simp_all add: abs_fresh ty_fresh) lemma typing_implies_valid: assumes a: "\ \ t : T" shows "valid \" using a by (induct) (auto dest: valid_elim) text {* Task 3 (hard) Prove the weakening property for the typing relation. You have to use typing.induct and avoid \2. *} lemma weakening: fixes \1 \2::"(name\ty) list" assumes a: "\1 \ t : T" and b: "valid \2" and c: "\1 \ \2" shows "\2 \ t : T" using a b c by (nominal_induct \1 t T avoiding: \2 rule: typing.strong_induct) (auto | atomize)+ text {* Task 4 (very hard) In order to prove the type-preservation property, we need to prove a type-substitution property. Prove it by induction on \ \ e : T and avoid e' and x. In the variable case you need, amongst other lemmas, the context_unique lemma. The lambda-case needs, amongst others, the weakening lemma. *} lemma type_substitution: fixes \::"(name\ty) list" assumes a: "\ \ e : T" and b: "(x,T')\set \" and c: "\ - [(x,T')] \ e': T'" shows "\ - [(x,T')] \ e[x::=e'] : T" using a b c proof (nominal_induct \ e T avoiding: e' x rule: typing.strong_induct) case (t1 \ y T e' x) have a1: "valid \" by fact have a2: "(y,T) \ set \" by fact have a3: "(x,T') \ set \" by fact have a4: "\ - [(x,T')] \ e' : T'" by fact { assume eq: "x=y" from a1 a2 a3 have "T=T'" using eq by (simp add: context_unique) with a4 have "\ - [(x,T')] \ Var y[x::=e'] : T" using eq by simp } moreover { assume ineq: "x\y" from a1 have "valid (\ - [(x,T')])" by (simp only: valid_diff) moreover from a3 have "(y,T) \ set (\ - [(x,T')])" using ineq by simp ultimately have "\ - [(x,T')] \ Var y[x::=e'] : T" using ineq by auto } ultimately show "\ - [(x,T')] \ Var y[x::=e'] : T" by blast next case (t3 y \ T\<^isub>1 t T\<^isub>2 e' x) have vc: "y\x" "y\e'" "y\\" by fact have a1: "(x, T') \ set \" by fact have a2: "\ - [(x,T')] \ e' : T'" by fact have a3: "(y,T\<^isub>1)#\ \ t : T\<^isub>2" by fact have ih: "\(x,T') \ set ((y,T\<^isub>1)#\); ((y,T\<^isub>1)#\) - [(x,T')] \ e' : T'\ \ ((y,T\<^isub>1)#\) - [(x,T')] \ (t[x::=e']) : T\<^isub>2" by fact have "(x,T') \ set ((y,T\<^isub>1)#\)" using a1 vc by (simp add: fresh_atm) moreover have "valid ((y,T\<^isub>1)#\)" using a3 by (simp add: typing_implies_valid) then have a5: "valid ((y,T\<^isub>1)#\) - [(x,T')]" by (simp only: valid_diff) then have "((y,T\<^isub>1)#\) - [(x,T')] \ e' : T'" using a2 by (auto intro: weakening) ultimately have "((y,T\<^isub>1)#\) - [(x,T')] \ (t[x::=e']) : T\<^isub>2" using ih by blast then have "(y,T\<^isub>1)#(\ - [(x,T')]) \ (t[x::=e']) : T\<^isub>2" using vc by (simp add: fresh_atm) moreover have "y\(\ - [(x,T')])" using vc by (simp only: fresh_diff) ultimately have "(\ - [(x,T')]) \ Lam [y].(t[x::=e']) : T\<^isub>1 \ T\<^isub>2" by blast then show "(\ - [(x,T')]) \ (Lam [y].t)[x::=e'] : T\<^isub>1 \ T\<^isub>2" using vc by simp qed (force) corollary type_substitution2: assumes a: "(x,T')#\ \ e : T" and b: "\ \ e' : T'" shows "\ \ e[x::=e'] : T" proof - from a have c: "valid ((x,T')#\)" by (simp add: typing_implies_valid) then have "x\\" by (auto dest: valid_elim) then have eq: "((x,T')#\) - [(x,T')] = \" by (induct \) (auto simp add: fresh_list_cons fresh_prod fresh_atm) with a b show "\ \ e[x::=e'] : T" by (auto dest: type_substitution) qed text {* Type inversion lemmas *} lemma t_Lam_inversion[dest]: assumes ty: "\ \ Lam [x].t : T" and fc: "x\\" shows "\T\<^isub>1 T\<^isub>2. T = T\<^isub>1 \ T\<^isub>2 \ (x,T\<^isub>1)#\ \ t : T\<^isub>2" using ty fc by (cases rule: typing.strong_cases) (auto simp add: alpha lam.inject abs_fresh ty_fresh) lemma t_App_inversion[dest]: assumes ty: "\ \ App t1 t2 : T" shows "\T'. \ \ t1 : T' \ T \ \ \ t2 : T'" using ty by (cases) (auto simp add: lam.inject) text {* Beta-reduction *} inductive "beta" :: "lam\lam\bool" (" _ \\<^isub>\ _") where b1[intro]: "t1 \\<^isub>\ t2 \ App t1 s \\<^isub>\ App t2 s" | b2[intro]: "s1 \\<^isub>\ s2 \ App t s1 \\<^isub>\ App t s2" | b3[intro]: "t1 \\<^isub>\ t2 \ Lam [x].t1 \\<^isub>\ Lam [x].t2" | b4[intro]: "x\s \ App (Lam [x].t) s \\<^isub>\ t[x::=s]" equivariance beta nominal_inductive beta by (auto simp add: abs_fresh fresh_fact) text {* Task 4 (easy) Now we can prove the type-preservation theorem. Prove it by induction over t \\<^isub>\ t' and avoid \ and T. *} theorem type_preservation: assumes a: "t \\<^isub>\ t'" and b: "\ \ t : T" shows "\ \ t' : T" using a b proof (nominal_induct avoiding: \ T rule: beta.strong_induct) case (b1 t1 t2 s \ T) have "\ \ App t1 s : T" by fact then obtain T' where a1: "\ \ t1 : T' \ T" and a2: "\ \ s : T'" by auto have ih: "\ \ t1 : T' \ T \ \ \ t2 : T' \ T" by fact with a1 a2 show "\ \ App t2 s : T" by auto next case (b2 s1 s2 t \ T) have "\ \ App t s1 : T" by fact then obtain T' where a1: "\ \ t : T' \ T" and a2: "\ \ s1 : T'" by auto have ih: "\ \ s1 : T' \ \ \ s2 : T'" by fact with a1 a2 show "\ \ App t s2 : T" by auto next case (b3 t1 t2 x \ T) have vc: "x\\" by fact have "\ \ Lam [x].t1 : T" by fact then obtain T1 T2 where a1: "(x,T1)#\ \ t1 : T2" and a2: "T = T1 \ T2" using vc by auto have ih: "(x,T1)#\ \ t1 : T2 \ (x,T1)#\ \ t2 : T2" by fact with a1 a2 show "\ \ Lam [x].t2 : T" using vc by auto next case (b4 x s t \ T) have vc: "x\\" by fact have "\ \ App (Lam [x].t) s : T" by fact then obtain T' where a1: "\ \ Lam [x].t : T' \ T" and a2: "\ \ s : T'" by auto from a1 obtain T1 T2 where a3: "(x,T')#\ \ t : T" using vc by (auto simp add: ty.inject) from a3 a2 show "\ \ t[x::=s] : T" by (simp add: type_substitution2) qed end