Theory Eta

(*  Title:      HOL/Proofs/Lambda/Eta.thy
    Author:     Tobias Nipkow and Stefan Berghofer
    Copyright   1995, 2005 TU Muenchen
*)

section ‹Eta-reduction›

theory Eta imports ParRed begin


subsection ‹Definition of eta-reduction and relatives›

primrec
  free :: "dB => nat => bool"
where
    "free (Var j) i = (j = i)"
  | "free (s ° t) i = (free s i  free t i)"
  | "free (Abs s) i = free s (i + 1)"

inductive
  eta :: "[dB, dB] => bool"  (infixl "η" 50)
where
    eta [simp, intro]: "¬ free s 0 ==> Abs (s ° Var 0) η s[dummy/0]"
  | appL [simp, intro]: "s η t ==> s ° u η t ° u"
  | appR [simp, intro]: "s η t ==> u ° s η u ° t"
  | abs [simp, intro]: "s η t ==> Abs s η Abs t"

abbreviation
  eta_reds :: "[dB, dB] => bool"   (infixl "η*" 50) where
  "s η* t == eta** s t"

abbreviation
  eta_red0 :: "[dB, dB] => bool"   (infixl "η=" 50) where
  "s η= t == eta== s t"

inductive_cases eta_cases [elim!]:
  "Abs s η z"
  "s ° t η u"
  "Var i η t"


subsection ‹Properties of eta›, subst› and free›

lemma subst_not_free [simp]: "¬ free s i  s[t/i] = s[u/i]"
  by (induct s arbitrary: i t u) (simp_all add: subst_Var)

lemma free_lift [simp]:
    "free (lift t k) i = (i < k  free t i  k < i  free t (i - 1))"
  apply (induct t arbitrary: i k)
  apply (auto cong: conj_cong)
  done

lemma free_subst [simp]:
    "free (s[t/k]) i =
      (free s k  free t i  free s (if i < k then i else i + 1))"
  apply (induct s arbitrary: i k t)
    prefer 2
    apply simp
    apply blast
   prefer 2
   apply simp
  apply (simp add: diff_Suc subst_Var split: nat.split)
  done

lemma free_eta: "s η t ==> free t i = free s i"
  by (induct arbitrary: i set: eta) (simp_all cong: conj_cong)

lemma not_free_eta:
    "[| s η t; ¬ free s i |] ==> ¬ free t i"
  by (simp add: free_eta)

lemma eta_subst [simp]:
    "s η t ==> s[u/i] η t[u/i]"
  by (induct arbitrary: u i set: eta) (simp_all add: subst_subst [symmetric])

theorem lift_subst_dummy: "¬ free s i  lift (s[dummy/i]) i = s"
  by (induct s arbitrary: i dummy) simp_all


subsection ‹Confluence of eta›

lemma square_eta: "square eta eta (eta==) (eta==)"
  apply (unfold square_def id_def)
  apply (rule impI [THEN allI [THEN allI]])
  apply (erule eta.induct)
     apply (slowsimp intro: subst_not_free eta_subst free_eta [THEN iffD1])
    apply safe
       prefer 5
       apply (blast intro!: eta_subst intro: free_eta [THEN iffD1])
      apply blast+
  done

theorem eta_confluent: "confluent eta"
  apply (rule square_eta [THEN square_reflcl_confluent])
  done


subsection ‹Congruence rules for eta*

lemma rtrancl_eta_Abs: "s η* s' ==> Abs s η* Abs s'"
  by (induct set: rtranclp)
    (blast intro: rtranclp.rtrancl_into_rtrancl)+

lemma rtrancl_eta_AppL: "s η* s' ==> s ° t η* s' ° t"
  by (induct set: rtranclp)
    (blast intro: rtranclp.rtrancl_into_rtrancl)+

lemma rtrancl_eta_AppR: "t η* t' ==> s ° t η* s ° t'"
  by (induct set: rtranclp) (blast intro: rtranclp.rtrancl_into_rtrancl)+

lemma rtrancl_eta_App:
    "[| s η* s'; t η* t' |] ==> s ° t η* s' ° t'"
  by (blast intro!: rtrancl_eta_AppL rtrancl_eta_AppR intro: rtranclp_trans)


subsection ‹Commutation of beta› and eta›

lemma free_beta:
    "s β t ==> free t i  free s i"
  by (induct arbitrary: i set: beta) auto

lemma beta_subst [intro]: "s β t ==> s[u/i] β t[u/i]"
  by (induct arbitrary: u i set: beta) (simp_all add: subst_subst [symmetric])

lemma subst_Var_Suc [simp]: "t[Var i/i] = t[Var(i)/i + 1]"
  by (induct t arbitrary: i) (auto elim!: linorder_neqE simp: subst_Var)

lemma eta_lift [simp]: "s η t ==> lift s i η lift t i"
  by (induct arbitrary: i set: eta) simp_all

lemma rtrancl_eta_subst: "s η t  u[s/i] η* u[t/i]"
  apply (induct u arbitrary: s t i)
    apply (simp_all add: subst_Var)
    apply blast
   apply (blast intro: rtrancl_eta_App)
  apply (blast intro!: rtrancl_eta_Abs eta_lift)
  done

lemma rtrancl_eta_subst':
  fixes s t :: dB
  assumes eta: "s η* t"
  shows "s[u/i] η* t[u/i]" using eta
  by induct (iprover intro: eta_subst)+

lemma rtrancl_eta_subst'':
  fixes s t :: dB
  assumes eta: "s η* t"
  shows "u[s/i] η* u[t/i]" using eta
  by induct (iprover intro: rtrancl_eta_subst rtranclp_trans)+

lemma square_beta_eta: "square beta eta (eta**) (beta==)"
  apply (unfold square_def)
  apply (rule impI [THEN allI [THEN allI]])
  apply (erule beta.induct)
     apply (slowsimp intro: rtrancl_eta_subst eta_subst)
    apply (blast intro: rtrancl_eta_AppL)
   apply (blast intro: rtrancl_eta_AppR)
  apply simp
  apply (slowsimp intro: rtrancl_eta_Abs free_beta
    iff del: dB.distinct simp: dB.distinct)    (*23 seconds?*)
  done

lemma confluent_beta_eta: "confluent (sup beta eta)"
  apply (assumption |
    rule square_rtrancl_reflcl_commute confluent_Un
      beta_confluent eta_confluent square_beta_eta)+
  done


subsection ‹Implicit definition of eta›

text termAbs (lift s 0 ° Var 0) η s

lemma not_free_iff_lifted:
    "(¬ free s i) = (t. s = lift t i)"
  apply (induct s arbitrary: i)
    apply simp
    apply (rule iffI)
     apply (erule linorder_neqE)
      apply (rename_tac nat a, rule_tac x = "Var nat" in exI)
      apply simp
     apply (rename_tac nat a, rule_tac x = "Var (nat - 1)" in exI)
     apply simp
    apply clarify
    apply (rule notE)
     prefer 2
     apply assumption
    apply (erule thin_rl)
    apply (case_tac t)
      apply simp
     apply simp
    apply simp
   apply simp
   apply (erule thin_rl)
   apply (erule thin_rl)
   apply (rule iffI)
    apply (elim conjE exE)
    apply (rename_tac u1 u2)
    apply (rule_tac x = "u1 ° u2" in exI)
    apply simp
   apply (erule exE)
   apply (erule rev_mp)
   apply (case_tac t)
     apply simp
    apply simp
    apply blast
   apply simp
  apply simp
  apply (erule thin_rl)
  apply (rule iffI)
   apply (erule exE)
   apply (rule_tac x = "Abs t" in exI)
   apply simp
  apply (erule exE)
  apply (erule rev_mp)
  apply (case_tac t)
    apply simp
   apply simp
  apply simp
  apply blast
  done

theorem explicit_is_implicit:
  "(s u. (¬ free s 0) --> R (Abs (s ° Var 0)) (s[u/0])) =
    (s. R (Abs (lift s 0 ° Var 0)) s)"
  by (auto simp add: not_free_iff_lifted)


subsection ‹Eta-postponement theorem›

text ‹
  Based on a paper proof due to Andreas Abel.
  Unlike the proof by Masako Takahashi cite"Takahashi-IandC", it does not
  use parallel eta reduction, which only seems to complicate matters unnecessarily.
›

theorem eta_case:
  fixes s :: dB
  assumes free: "¬ free s 0"
  and s: "s[dummy/0] => u"
  shows "t'. Abs (s ° Var 0) => t'  t' η* u"
proof -
  from s have "lift (s[dummy/0]) 0 => lift u 0" by (simp del: lift_subst)
  with free have "s => lift u 0" by (simp add: lift_subst_dummy del: lift_subst)
  hence "Abs (s ° Var 0) => Abs (lift u 0 ° Var 0)" by simp
  moreover have "¬ free (lift u 0) 0" by simp
  hence "Abs (lift u 0 ° Var 0) η lift u 0[dummy/0]"
    by (rule eta.eta)
  hence "Abs (lift u 0 ° Var 0) η* u" by simp
  ultimately show ?thesis by iprover
qed

theorem eta_par_beta:
  assumes st: "s η t"
  and tu: "t => u"
  shows "t'. s => t'  t' η* u" using tu st
proof (induct arbitrary: s)
  case (var n)
  thus ?case by (iprover intro: par_beta_refl)
next
  case (abs s' t)
  note abs' = this
  from s η Abs s' show ?case
  proof cases
    case (eta s'' dummy)
    from abs have "Abs s' => Abs t" by simp
    with eta have "s''[dummy/0] => Abs t" by simp
    with ¬ free s'' 0 have "t'. Abs (s'' ° Var 0) => t'  t' η* Abs t"
      by (rule eta_case)
    with eta show ?thesis by simp
  next
    case (abs r)
    from r η s'
    obtain t' where r: "r => t'" and t': "t' η* t" by (iprover dest: abs')
    from r have "Abs r => Abs t'" ..
    moreover from t' have "Abs t' η* Abs t" by (rule rtrancl_eta_Abs)
    ultimately show ?thesis using abs by simp iprover
  qed
next
  case (app u u' t t')
  from s η u ° t show ?case
  proof cases
    case (eta s' dummy)
    from app have "u ° t => u' ° t'" by simp
    with eta have "s'[dummy/0] => u' ° t'" by simp
    with ¬ free s' 0 have "r. Abs (s' ° Var 0) => r  r η* u' ° t'"
      by (rule eta_case)
    with eta show ?thesis by simp
  next
    case (appL s')
    from s' η u
    obtain r where s': "s' => r" and r: "r η* u'" by (iprover dest: app)
    from s' and app have "s' ° t => r ° t'" by simp
    moreover from r have "r ° t' η* u' ° t'" by (simp add: rtrancl_eta_AppL)
    ultimately show ?thesis using appL by simp iprover
  next
    case (appR s')
    from s' η t
    obtain r where s': "s' => r" and r: "r η* t'" by (iprover dest: app)
    from s' and app have "u ° s' => u' ° r" by simp
    moreover from r have "u' ° r η* u' ° t'" by (simp add: rtrancl_eta_AppR)
    ultimately show ?thesis using appR by simp iprover
  qed
next
  case (beta u u' t t')
  from s η Abs u ° t show ?case
  proof cases
    case (eta s' dummy)
    from beta have "Abs u ° t => u'[t'/0]" by simp
    with eta have "s'[dummy/0] => u'[t'/0]" by simp
    with ¬ free s' 0 have "r. Abs (s' ° Var 0) => r  r η* u'[t'/0]"
      by (rule eta_case)
    with eta show ?thesis by simp
  next
    case (appL s')
    from s' η Abs u show ?thesis
    proof cases
      case (eta s'' dummy)
      have "Abs (lift u 1) = lift (Abs u) 0" by simp
      also from eta have " = s''" by (simp add: lift_subst_dummy del: lift_subst)
      finally have s: "s = Abs (Abs (lift u 1) ° Var 0) ° t" using appL and eta by simp
      from beta have "lift u 1 => lift u' 1" by simp
      hence "Abs (lift u 1) ° Var 0 => lift u' 1[Var 0/0]"
        using par_beta.var ..
      hence "Abs (Abs (lift u 1) ° Var 0) ° t => lift u' 1[Var 0/0][t'/0]"
        using t => t' ..
      with s have "s => u'[t'/0]" by simp
      thus ?thesis by iprover
    next
      case (abs r)
      from r η u
      obtain r'' where r: "r => r''" and r'': "r'' η* u'" by (iprover dest: beta)
      from r and beta have "Abs r ° t => r''[t'/0]" by simp
      moreover from r'' have "r''[t'/0] η* u'[t'/0]"
        by (rule rtrancl_eta_subst')
      ultimately show ?thesis using abs and appL by simp iprover
    qed
  next
    case (appR s')
    from s' η t
    obtain r where s': "s' => r" and r: "r η* t'" by (iprover dest: beta)
    from s' and beta have "Abs u ° s' => u'[r/0]" by simp
    moreover from r have "u'[r/0] η* u'[t'/0]"
      by (rule rtrancl_eta_subst'')
    ultimately show ?thesis using appR by simp iprover
  qed
qed

theorem eta_postponement':
  assumes eta: "s η* t" and beta: "t => u"
  shows "t'. s => t'  t' η* u" using eta beta
proof (induct arbitrary: u)
  case base
  thus ?case by blast
next
  case (step s' s'' s''')
  then obtain t' where s': "s' => t'" and t': "t' η* s'''"
    by (auto dest: eta_par_beta)
  from s' obtain t'' where s: "s => t''" and t'': "t'' η* t'" using step
    by blast
  from t'' and t' have "t'' η* s'''" by (rule rtranclp_trans)
  with s show ?case by iprover
qed

theorem eta_postponement:
  assumes "(sup beta eta)** s t"
  shows "(beta** OO eta**) s t" using assms
proof induct
  case base
  show ?case by blast
next
  case (step s' s'')
  from step(3) obtain t' where s: "s β* t'" and t': "t' η* s'" by blast
  from step(2) show ?case
  proof
    assume "s' β s''"
    with beta_subset_par_beta have "s' => s''" ..
    with t' obtain t'' where st: "t' => t''" and tu: "t'' η* s''"
      by (auto dest: eta_postponement')
    from par_beta_subset_beta st have "t' β* t''" ..
    with s have "s β* t''" by (rule rtranclp_trans)
    thus ?thesis using tu ..
  next
    assume "s' η s''"
    with t' have "t' η* s''" ..
    with s show ?thesis ..
  qed
qed

end