Theory SN
theory SN
imports Lam_Funs
begin
text ‹Strong Normalisation proof from the Proofs and Types book›
section ‹Beta Reduction›
lemma subst_rename: 
  assumes a: "c♯t1"
  shows "t1[a::=t2] = ([(c,a)]∙t1)[c::=t2]"
using a
by (nominal_induct t1 avoiding: a c t2 rule: lam.strong_induct)
   (auto simp add: calc_atm fresh_atm abs_fresh)
lemma forget: 
  assumes a: "a♯t1"
  shows "t1[a::=t2] = t1"
  using a
by (nominal_induct t1 avoiding: a t2 rule: lam.strong_induct)
   (auto simp add: abs_fresh fresh_atm)
lemma fresh_fact: 
  fixes a::"name"
  assumes a: "a♯t1" "a♯t2"
  shows "a♯t1[b::=t2]"
using a
by (nominal_induct t1 avoiding: a b t2 rule: lam.strong_induct)
   (auto simp add: abs_fresh fresh_atm)
lemma fresh_fact': 
  fixes a::"name"
  assumes a: "a♯t2"
  shows "a♯t1[a::=t2]"
using a 
by (nominal_induct t1 avoiding: a t2 rule: lam.strong_induct)
   (auto simp add: abs_fresh fresh_atm)
lemma subst_lemma:  
  assumes a: "x≠y"
  and     b: "x♯L"
  shows "M[x::=N][y::=L] = M[y::=L][x::=N[y::=L]]"
using a b
by (nominal_induct M avoiding: x y N L rule: lam.strong_induct)
   (auto simp add: fresh_fact forget)
lemma id_subs: 
  shows "t[x::=Var x] = t"
  by (nominal_induct t avoiding: x rule: lam.strong_induct)
     (simp_all add: fresh_atm)
lemma lookup_fresh:
  fixes z::"name"
  assumes "z♯θ" "z♯x"
  shows "z♯ lookup θ x"
using assms 
by (induct rule: lookup.induct) (auto simp add: fresh_list_cons)
lemma lookup_fresh':
  assumes "z♯θ"
  shows "lookup θ z = Var z"
using assms 
by (induct rule: lookup.induct)
   (auto simp add: fresh_list_cons fresh_prod fresh_atm)
lemma psubst_subst:
  assumes h:"c♯θ"
  shows "(θ<t>)[c::=s] = ((c,s)#θ)<t>"
  using h
by (nominal_induct t avoiding: θ c s rule: lam.strong_induct)
   (auto simp add: fresh_list_cons fresh_atm forget lookup_fresh lookup_fresh')
 
inductive 
  Beta :: "lam⇒lam⇒bool" (‹ _ ⟶⇩β _› [80,80] 80)
where
  b1[intro!]: "s1 ⟶⇩β s2 ⟹ App s1 t ⟶⇩β App s2 t"
| b2[intro!]: "s1⟶⇩βs2 ⟹ App t s1 ⟶⇩β App t s2"
| b3[intro!]: "s1⟶⇩βs2 ⟹ Lam [a].s1 ⟶⇩β Lam [a].s2"
| b4[intro!]: "a♯s2 ⟹ App (Lam [a].s1) s2⟶⇩β (s1[a::=s2])"
equivariance Beta
nominal_inductive Beta
  by (simp_all add: abs_fresh fresh_fact')
lemma beta_preserves_fresh: 
  fixes a::"name"
  assumes a: "t⟶⇩β s"
  shows "a♯t ⟹ a♯s"
using a
  by (nominal_induct t s avoiding: a rule: Beta.strong_induct)
     (auto simp add: abs_fresh fresh_fact fresh_atm)
lemma beta_abs: 
  assumes a: "Lam [a].t⟶⇩β t'" 
  shows "∃t''. t'=Lam [a].t'' ∧ t⟶⇩β t''"
proof -
  have "a♯Lam [a].t" by (simp add: abs_fresh)
  with a have "a♯t'" by (simp add: beta_preserves_fresh)
  with a show ?thesis
    by (cases rule: Beta.strong_cases[where a="a" and aa="a"])
       (auto simp add: lam.inject abs_fresh alpha)
qed
lemma beta_subst: 
  assumes a: "M ⟶⇩β M'"
  shows "M[x::=N]⟶⇩β M'[x::=N]" 
using a
by (nominal_induct M M' avoiding: x N rule: Beta.strong_induct)
   (auto simp add: fresh_atm subst_lemma fresh_fact)
section ‹types›