Theory System_F_Erasure

theory System_F_Erasure
  imports System_F System_F_Untyped
begin

fun f_erase :: "dtm  ulam" where
  "f_erase (TmVar n) = UVar n"
| "f_erase (TmApp M N) = UApp (f_erase M) (f_erase N)"
| "f_erase (TmLam A M) = ULam (f_erase M)"
| "f_erase (TmTAbs M) = f_erase M"
| "f_erase (TmTApp M A) = f_erase M"

lemma f_erase_tm_shift:
  "f_erase (tm_shift k M) = u_shift k (f_erase M)"
  by (induct M arbitrary: k rule: dtm.induct) simp_all

lemma f_erase_tm_ty_shift:
  "f_erase (tm_ty_shift k M) = f_erase M"
  by (induct M arbitrary: k rule: dtm.induct) simp_all

lemma f_erase_tm_subst:
  "f_erase (tm_subst k N M) =
    u_subst k (f_erase N) (f_erase M)"
  by (induct M arbitrary: k N rule: dtm.induct)
     (simp_all add: f_erase_tm_shift f_erase_tm_ty_shift)

lemma f_erase_tm_ty_subst:
  "f_erase (tm_ty_subst k S M) = f_erase M"
  by (induct M arbitrary: k S rule: dtm.induct) simp_all

lemma f_erase_tm_subst0:
  "f_erase (tm_subst0 N M) =
    u_subst0 (f_erase N) (f_erase M)"
  by (simp add: tm_subst0_def u_subst0_def f_erase_tm_subst)

lemma f_erase_tm_ty_subst0:
  "f_erase (tm_ty_subst0 S M) = f_erase M"
  by (simp add: tm_ty_subst0_def f_erase_tm_ty_subst)

fun f_type_count :: "dtm  nat" where
  "f_type_count (TmVar n) = 0"
| "f_type_count (TmApp M N) = f_type_count M + f_type_count N"
| "f_type_count (TmLam A M) = f_type_count M"
| "f_type_count (TmTAbs M) = Suc (f_type_count M)"
| "f_type_count (TmTApp M A) = Suc (f_type_count M)"

lemma f_type_count_tm_ty_subst:
  "f_type_count (tm_ty_subst k S M) = f_type_count M"
  by (induct M arbitrary: k S rule: dtm.induct) simp_all

lemma f_type_count_tm_ty_subst0:
  "f_type_count (tm_ty_subst0 S M) = f_type_count M"
  by (simp add: tm_ty_subst0_def f_type_count_tm_ty_subst)

lemma f_beta_progress:
  assumes "M β M'"
  shows "ubeta (f_erase M) (f_erase M') 
    f_erase M = f_erase M' 
      f_type_count M' < f_type_count M"
  using assms
proof (induct rule: beta.induct)
  case beta_appL
  then show ?case
    by (auto intro: ubeta.uappL)
next
  case beta_appR
  then show ?case
    by (auto intro: ubeta.uappR)
next
  case beta_lam
  then show ?case
    by (auto intro: ubeta.ulam)
next
  case beta_tabs
  then show ?case
    by auto
next
  case beta_tapp
  then show ?case
    by auto
next
  case (beta_term A M N)
  have root:
    "ubeta (UApp (ULam (f_erase M)) (f_erase N))
      (u_subst0 (f_erase N) (f_erase M))"
    by (rule ubeta.ured)
  then show ?case
    by (simp add: f_erase_tm_subst0 u_subst0_def)
next
  case beta_type
  then show ?case
    by (rule disjI2;
      simp add: f_erase_tm_ty_subst0 f_type_count_tm_ty_subst0)
qed

lemma fSN_reflect:
  assumes "uSN (f_erase M)"
  shows "SN M"
proof -
  have aux: "U. uSN U 
      M. f_erase M = U  SN M"
  proof -
    fix U
    assume "uSN U"
    then show "M. f_erase M = U  SN M"
    proof (induct rule: uSN.induct)
      case (uSN_intro U)
      show ?case
      proof (intro allI impI)
        fix M
        assume eM: "f_erase M = U"
        have type_aux:
          "n. X. f_type_count X = n 
            f_erase X = U  SN X"
        proof -
          fix n
          show "X. f_type_count X = n 
            f_erase X = U  SN X"
          proof (induct n rule: less_induct)
            case (less n)
            show ?case
            proof (intro allI impI impI)
              fix X
              assume countX: "f_type_count X = n"
              assume eX: "f_erase X = U"
              show "SN X"
              proof (rule SN.SN_intro)
                fix X'
                assume red: "X β X'"
                have prog:
                  "ubeta (f_erase X) (f_erase X') 
                    f_erase X = f_erase X' 
                      f_type_count X' < f_type_count X"
                  using f_beta_progress[OF red] .
                then show "SN X'"
                proof (elim disjE)
                  assume ured: "ubeta (f_erase X) (f_erase X')"
                  have ured': "U u f_erase X'"
                    using ured by (simp only: eX[symmetric])
                  have ih:
                    "R. f_erase X' = f_erase R  SN R"
                  proof (intro allI impI)
                    fix R
                    assume eq: "f_erase X' = f_erase R"
                    have eq': "f_erase R = f_erase X'"
                      using eq by simp
                    from uSN_intro(2)[OF ured'] show "SN R"
                      using eq' by blast
                  qed
                  from ih show "SN X'" by blast
                next
                  assume dec:
                    "f_erase X = f_erase X' 
                      f_type_count X' < f_type_count X"
                  have count_lt: "f_type_count X' < n"
                    using countX dec by arith
                  have ih:
                    "R. f_type_count R = f_type_count X' 
                      f_erase R = U  SN R"
                    using less[of "f_type_count X'"] count_lt by blast
                  have eEq: "f_erase X = f_erase X'"
                    using dec by blast
                  have eX': "f_erase X' = U"
                    using eEq eX by simp
                  from ih eX' show "SN X'" by simp
                qed
              qed
            qed
          qed
        qed
        from type_aux[of "f_type_count M"] eM
        show "SN M" by simp
      qed
    qed
  qed
  then show "SN M" using assms by blast
qed

end