Theory Resumption

(*  Author:      Andreas Lochbihler
    Maintainer:  Andreas Lochbihler
*)
section ‹Manual construction of a resumption codatatype›

theory Resumption imports 
  "HOL-Library.Old_Datatype"
begin

text ‹
  This theory defines the following codatatype:

\begin{verbatim}
codatatype ('a,'b,'c,'d) resumption =
    Terminal 'a
  | Linear 'b "('a,'b,'c,'d) resumption"
  | Branch 'c "'d => ('a,'b,'c,'d) resumption"
\end{verbatim}

›

subsection ‹Auxiliary definitions and lemmata similar to @{theory "HOL-Library.Old_Datatype"}›

lemma Lim_mono: "(⋀d. rs d ⊆ rs' d) ⟹ Old_Datatype.Lim rs ⊆ Old_Datatype.Lim rs'"
by(simp add: Lim_def) blast

lemma Lim_UN1:  "Old_Datatype.Lim (λx. ⋃y. f x y) = (⋃y. Old_Datatype.Lim (λx. f x y))"
by(simp add: Old_Datatype.Lim_def) blast

text ‹
  Inverse for @{term "Old_Datatype.Lim"} like @{term "Old_Datatype.Split"} and @{term "Old_Datatype.Case"}
  for @{term "Old_Datatype.Scons"} and @{term "In0"}/@{term "In1"}
›

definition DTBranch :: "(('b ⇒ ('a, 'b) Old_Datatype.dtree) ⇒ 'c) ⇒ ('a, 'b) Old_Datatype.dtree ⇒ 'c"
where "DTBranch f M = (THE u. ∃x. M = Old_Datatype.Lim x ∧ u = f x)"

lemma DTBranch_Lim [simp]: "DTBranch f (Old_Datatype.Lim M) = f M"
by(auto simp add: DTBranch_def dest: Lim_inject)

text ‹Lemmas for @{term Old_Datatype.ntrunc} and @{term "Old_Datatype.Lim"}›

lemma ndepth_Push_Node_Inl_aux:
     "case_nat (Inl n) f k = Inr 0 ⟹ Suc (LEAST x. f x = Inr 0) <= k"
apply (induct "k", auto)
apply (erule Least_le)
done

lemma ndepth_Push_Node_Inl:
  "ndepth (Push_Node (Inl a) n) = Suc (ndepth n)"
using Rep_Node[of n, unfolded Node_def]
apply(simp add: ndepth_def Push_Node_def Abs_Node_inverse[OF Node_Push_I[OF Rep_Node]])
apply(simp add: Push_def split_beta)
apply(rule Least_equality)
apply(auto elim: LeastI intro: ndepth_Push_Node_Inl_aux)
done

lemma ntrunc_Lim [simp]: "ntrunc (Suc k) (Old_Datatype.Lim rs) = Old_Datatype.Lim (λx. ntrunc k (rs x))"
unfolding Lim_def ntrunc_def
apply(rule equalityI)
apply clarify
apply(auto simp add: ndepth_Push_Node_Inl)
done

subsection ‹Definition for the codatatype universe›

text ‹Constructors›

definition TERMINAL :: "'a ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree"
where "TERMINAL a = In0 (Old_Datatype.Leaf (Inr (Inr a)))"

definition LINEAR :: "'b ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree"
  where "LINEAR b r = In1 (In0 (Scons (Old_Datatype.Leaf (Inr (Inl b))) r))"

definition BRANCH :: "'c ⇒ ('d ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree) ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree"
 where "BRANCH c rs = In1 (In1 (Scons (Old_Datatype.Leaf (Inl c)) (Old_Datatype.Lim rs)))"

text ‹case operator›

definition case_RESUMPTION :: "('a ⇒ 'e) ⇒ ('b ⇒ (('c + 'b + 'a, 'd) Old_Datatype.dtree) ⇒ 'e) ⇒ ('c ⇒ ('d ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree) ⇒ 'e) ⇒ ('c + 'b + 'a, 'd) Old_Datatype.dtree ⇒ 'e"
where 
  "case_RESUMPTION t l br =
   Old_Datatype.Case (t o inv (Old_Datatype.Leaf o Inr o Inr))
                 (Old_Datatype.Case (Old_Datatype.Split (λx. l (inv (Old_Datatype.Leaf o Inr o Inl) x)))
                                (Old_Datatype.Split (λx. DTBranch (br (inv (Old_Datatype.Leaf o Inl) x)))))"

lemma [iff]:
  shows TERMINAL_not_LINEAR: "TERMINAL a ≠ LINEAR b r"
  and LINEAR_not_TERMINAL: "LINEAR b R ≠ TERMINAL a"
  and TERMINAL_not_BRANCH: "TERMINAL a ≠ BRANCH c rs"
  and BRANCH_not_TERMINAL: "BRANCH c rs ≠ TERMINAL a"
  and LINEAR_not_BRANCH: "LINEAR b r ≠ BRANCH c rs"
  and BRANCH_not_LINEAR: "BRANCH c rs ≠ LINEAR b r"
  and TERMINAL_inject: "TERMINAL a = TERMINAL a' ⟷ a = a'"
  and LINEAR_inject: "LINEAR b r = LINEAR b' r' ⟷ b = b' ∧ r = r'"
  and BRANCH_inject: "BRANCH c rs = BRANCH c' rs' ⟷ c = c' ∧ rs = rs'"
by(auto simp add: TERMINAL_def LINEAR_def BRANCH_def dest: Lim_inject)

lemma case_RESUMPTION_simps [simp]:
  shows case_RESUMPTION_TERMINAL: "case_RESUMPTION t l br (TERMINAL a) = t a"
  and case_RESUMPTION_LINEAR: "case_RESUMPTION t l br (LINEAR b r) = l b r"
  and case_RESUMPTION_BRANCH: "case_RESUMPTION t l br (BRANCH c rs) = br c rs"
apply(simp_all add: case_RESUMPTION_def TERMINAL_def LINEAR_def BRANCH_def o_def)
apply(rule arg_cong) back
apply(blast intro: injI inv_f_f)
apply(rule arg_cong) back
apply(blast intro: injI inv_f_f)
apply(rule arg_cong) back
apply(blast intro: injI inv_f_f)
done

lemma LINEAR_mono: "r ⊆ r' ⟹ LINEAR b r ⊆ LINEAR b r'"
by(simp add: LINEAR_def In1_mono In0_mono Scons_mono)

lemma BRANCH_mono: "(⋀d. rs d ⊆ rs' d) ⟹ BRANCH c rs ⊆ BRANCH c rs'"
by(simp add: BRANCH_def In1_mono Scons_mono Lim_mono)

lemma LINEAR_UN: "LINEAR b (⋃x. f x) = (⋃x. LINEAR b (f x))"
by (simp add: LINEAR_def In1_UN1 In0_UN1 Scons_UN1_y)

lemma BRANCH_UN: "BRANCH b (λd. ⋃x. f d x) = (⋃x. BRANCH b (λd. f d x))"
by (simp add: BRANCH_def Lim_UN1 In1_UN1 In0_UN1 Scons_UN1_y)

text ‹The codatatype universe›

coinductive_set resumption :: "('c + 'b + 'a, 'd) Old_Datatype.dtree set"
where
resumption_TERMINAL:
  "TERMINAL a ∈ resumption"
| resumption_LINEAR:
  "r ∈ resumption ⟹ LINEAR b r ∈ resumption"
| resumption_BRANCH:
  "(⋀d. rs d ∈ resumption) ⟹ BRANCH c rs ∈ resumption"

subsection ‹Definition of the codatatype as a type›

typedef ('a,'b,'c,'d) resumption = "resumption :: ('c + 'b + 'a, 'd) Old_Datatype.dtree set"
proof
  show "TERMINAL undefined ∈ ?resumption" by(blast intro: resumption.intros)
qed

text ‹Constructors›

definition Terminal :: "'a ⇒ ('a,'b,'c,'d) resumption"
where "Terminal a = Abs_resumption (TERMINAL a)"

definition Linear :: "'b ⇒ ('a,'b,'c,'d) resumption ⇒ ('a,'b,'c,'d) resumption"
where "Linear b r = Abs_resumption (LINEAR b (Rep_resumption r))"

definition Branch :: "'c ⇒ ('d ⇒ ('a,'b,'c,'d) resumption) ⇒ ('a,'b,'c,'d) resumption"
where "Branch c rs = Abs_resumption (BRANCH c (λd. Rep_resumption (rs d)))"

lemma [iff]:
  shows Terminal_not_Linear: "Terminal a ≠ Linear b r"
  and Linear_not_Terminal: "Linear b R ≠ Terminal a"
  and Termina_not_Branch: "Terminal a ≠ Branch c rs"
  and Branch_not_Terminal: "Branch c rs ≠ Terminal a"
  and Linear_not_Branch: "Linear b r ≠ Branch c rs"
  and Branch_not_Linear: "Branch c rs ≠ Linear b r"
  and Terminal_inject: "Terminal a = Terminal a' ⟷ a = a'"
  and Linear_inject: "Linear b r = Linear b' r' ⟷ b = b' ∧ r = r'"
  and Branch_inject: "Branch c rs = Branch c' rs' ⟷ c = c' ∧ rs = rs'"
apply(auto simp add: Terminal_def Linear_def Branch_def simp add: Rep_resumption resumption.intros Abs_resumption_inject Rep_resumption_inject)
apply(subst (asm) fun_eq_iff, auto simp add: Rep_resumption_inject)
done

lemma Rep_resumption_constructors:
  shows Rep_resumption_Terminal: "Rep_resumption (Terminal a) = TERMINAL a"
  and Rep_resumption_Linear: "Rep_resumption (Linear b r) = LINEAR b (Rep_resumption r)"
  and Rep_resumption_Branch: "Rep_resumption (Branch c rs) = BRANCH c (λd. Rep_resumption (rs d))"
by(simp_all add: Terminal_def Linear_def Branch_def Abs_resumption_inverse resumption.intros Rep_resumption)

text ‹Case operator›

definition case_resumption :: "('a ⇒ 'e) ⇒ ('b ⇒ ('a,'b,'c,'d) resumption ⇒ 'e) ⇒
                            ('c ⇒ ('d ⇒ ('a,'b,'c,'d) resumption) ⇒ 'e) ⇒ ('a,'b,'c,'d) resumption ⇒ 'e"
where
  "case_resumption t l br r =
   case_RESUMPTION t (λb r. l b (Abs_resumption r)) (λc rs. br c (λd. Abs_resumption (rs d))) (Rep_resumption r)"

lemma case_resumption_simps [simp, code]:
  shows case_resumption_Terminal: "case_resumption t l br (Terminal a) = t a"
  and case_resumption_Linear: "case_resumption t l br (Linear b r) = l b r"
  and case_resumption_Branch: "case_resumption t l br (Branch c rs) = br c rs"
by(simp_all add: Terminal_def Linear_def Branch_def case_resumption_def Abs_resumption_inverse resumption.intros Rep_resumption Rep_resumption_inverse)

declare [[case_translation case_resumption Terminal Linear Branch]]

lemma case_resumption_cert:
  assumes "CASE ≡ case_resumption t l br"
  shows "(CASE (Terminal a) ≡ t a) &&& (CASE (Linear b r) ≡ l b r) &&& (CASE (Branch c rs) ≡ br c rs)"
using assms by simp_all

code_datatype Terminal Linear Branch

setup ‹Code.declare_case_global @{thm case_resumption_cert}›

setup ‹
  Nitpick.register_codatatype @{typ "('a,'b,'c,'d) resumption"} @{const_name case_resumption}
                              (map dest_Const [@{term Terminal}, @{term Linear}, @{term Branch}])
›

lemma resumption_exhaust [cases type: resumption]:
  obtains (Terminal) a where "x = Terminal a"
  | (Linear) b r where "x = Linear b r"
  | (Branch) c rs where "x = Branch c rs"
proof(cases x)
  case (Abs_resumption y)
  note [simp] = ‹x = Abs_resumption y›
  from ‹y ∈ resumption› show thesis
  proof(cases rule: resumption.cases)
    case resumption_TERMINAL thus ?thesis
      by -(rule Terminal, simp add: Terminal_def)
  next
    case (resumption_LINEAR r b) 
    from ‹r ∈ resumption› have "Rep_resumption (Abs_resumption r) = r"
      by(simp add: Abs_resumption_inverse)
    hence "y = LINEAR b (Rep_resumption (Abs_resumption r))"
      using ‹y = LINEAR b r› by simp
    thus ?thesis by -(rule Linear, simp add: Linear_def)
  next
    case (resumption_BRANCH rs c)
    from ‹⋀d. rs d ∈ resumption›
    have eq: "rs = (λd. Rep_resumption (Abs_resumption (rs d)))"
      by(subst Abs_resumption_inverse) blast+
    show ?thesis using ‹y = BRANCH c rs› 
      by -(rule Branch, simp add: Branch_def, subst eq, simp)
  qed
qed

lemma resumption_split:
  "P (case_resumption t l br r) ⟷ 
  (∀a. r = Terminal a ⟶ P (t a)) ∧
  (∀b r'. r = Linear b r' ⟶ P (l b r')) ∧
  (∀c rs. r = Branch c rs ⟶ P (br c rs))"
by(cases r) simp_all

lemma resumption_split_asm:
  "P (case_resumption t l br r) ⟷
  ¬ ((∃a. r = Terminal a ∧ ¬ P (t a)) ∨
     (∃b r'. r = Linear b r' ∧ ¬ P (l b r')) ∨
     (∃c rs. r = Branch c rs ∧ ¬ P (br c rs)))"
by(cases r) simp_all

lemmas resumption_splits = resumption_split resumption_split_asm


text ‹corecursion operator›

datatype (dead 'a, dead 'b, dead 'c, dead 'd, dead 'e) resumption_corec =
    Terminal_corec 'a
  | Linear_corec 'b 'e
  | Branch_corec 'c "'d ⇒ 'e"
  | Resumption_corec "('a, 'b, 'c, 'd) resumption"

primrec RESUMPTION_corec_aux :: "nat ⇒ ('e ⇒ ('a,'b,'c,'d,'e) resumption_corec) ⇒ 'e ⇒ ('c + 'b + 'a,'d) Old_Datatype.dtree"
where
  "RESUMPTION_corec_aux 0 f e = {}"
| "RESUMPTION_corec_aux (Suc n) f e =
  (case f e of Terminal_corec a ⇒ TERMINAL a
            | Linear_corec b e' ⇒ LINEAR b (RESUMPTION_corec_aux n f e')
            | Branch_corec c es ⇒ BRANCH c (λd. RESUMPTION_corec_aux n f (es d))
            | Resumption_corec r ⇒ Rep_resumption r)"

definition RESUMPTION_corec :: "('e ⇒ ('a,'b,'c,'d,'e) resumption_corec) ⇒ 'e ⇒ ('c + 'b + 'a,'d) Old_Datatype.dtree"
where
  "RESUMPTION_corec f e = (⋃n. RESUMPTION_corec_aux n f e)"

lemma RESUMPTION_corec [nitpick_simp]:
  "RESUMPTION_corec f e =
  (case f e of Terminal_corec a ⇒ TERMINAL a
            | Linear_corec b e' ⇒ LINEAR b (RESUMPTION_corec f e')
            | Branch_corec c es ⇒ BRANCH c (λd. RESUMPTION_corec f (es d))
            | Resumption_corec r ⇒ Rep_resumption r)"
  (is "?lhs = ?rhs")
proof
  show "?lhs ⊆ ?rhs" unfolding RESUMPTION_corec_def
  proof(rule UN_least)
    fix n
    show "RESUMPTION_corec_aux n f e
        ⊆ (case f e of Terminal_corec a ⇒ TERMINAL a
           | Linear_corec b e' ⇒ LINEAR b (⋃n. RESUMPTION_corec_aux n f e')
           | Branch_corec c es ⇒ BRANCH c (λd. ⋃n. RESUMPTION_corec_aux n f (es d))
           | Resumption_corec r ⇒ Rep_resumption r)"
      apply(cases n, simp_all split: resumption_corec.split)
      by(rule conjI strip LINEAR_mono[OF UN_upper] BRANCH_mono[OF UN_upper] UNIV_I)+
  qed
next
  show "?rhs ⊆ ?lhs" unfolding RESUMPTION_corec_def
    apply(simp split: resumption_corec.split add: LINEAR_UN BRANCH_UN)
    by safe(rule_tac a="Suc n" for n in UN_I, rule UNIV_I, simp)+
qed

lemma RESUMPTION_corec_type: "RESUMPTION_corec f e ∈ resumption"
proof -
  have "∃x. RESUMPTION_corec f e = RESUMPTION_corec f x" by blast
  thus ?thesis
  proof coinduct
    case (resumption x)
    then obtain e where x: "x = RESUMPTION_corec f e" by blast
    thus ?case 
    proof(cases "f e")
      case (Resumption_corec r)
      thus ?thesis using x
        by(cases r)(simp_all add: RESUMPTION_corec Rep_resumption_constructors Rep_resumption)
    qed(auto simp add: RESUMPTION_corec)
  qed
qed

text ‹corecursion operator for the resumption type›

definition resumption_corec :: "('e ⇒ ('a,'b,'c,'d,'e) resumption_corec) ⇒ 'e ⇒ ('a,'b,'c,'d) resumption"
where
  "resumption_corec f e = Abs_resumption (RESUMPTION_corec f e)"

lemma resumption_corec:
  "resumption_corec f e =
  (case f e of Terminal_corec a ⇒ Terminal a
            | Linear_corec b e' ⇒ Linear b (resumption_corec f e')
            | Branch_corec c es ⇒ Branch c (λd. resumption_corec f (es d))
            | Resumption_corec r ⇒ r)"
unfolding resumption_corec_def
apply(subst RESUMPTION_corec)
apply(auto split: resumption_corec.splits simp add: Terminal_def Linear_def Branch_def RESUMPTION_corec_type Abs_resumption_inverse Rep_resumption_inverse)
done

text ‹Equality as greatest fixpoint›

coinductive Eq_RESUMPTION :: "('c+'b+'a, 'd) Old_Datatype.dtree ⇒ ('c+'b+'a, 'd) Old_Datatype.dtree ⇒ bool"
where
  EqTERMINAL: "Eq_RESUMPTION (TERMINAL a) (TERMINAL a)"
| EqLINEAR: "Eq_RESUMPTION r r' ⟹ Eq_RESUMPTION (LINEAR b r) (LINEAR b r')"
| EqBRANCH: "(⋀d. Eq_RESUMPTION (rs d) (rs' d)) ⟹ Eq_RESUMPTION (BRANCH c rs) (BRANCH c rs')"

lemma Eq_RESUMPTION_implies_ntrunc_equality:
  "Eq_RESUMPTION r r' ⟹ ntrunc k r = ntrunc k r'"
proof(induct k arbitrary: r r' rule: less_induct)
  case (less k)
  note IH = ‹⋀k' r r'. ⟦k' < k; Eq_RESUMPTION r r'⟧ ⟹ ntrunc k' r = ntrunc k' r'›
  from ‹Eq_RESUMPTION r r'› show ?case
  proof cases
    case EqTERMINAL
    thus ?thesis by simp
  next
    case (EqLINEAR R R' b)
    thus ?thesis unfolding LINEAR_def
      apply(cases k, simp)
      apply(rename_tac k', case_tac k', simp)
      apply(rename_tac k'', case_tac k'', simp_all add: IH)
      done
  next
    case (EqBRANCH rs rs' c)
    thus ?thesis unfolding BRANCH_def
      apply(cases k, simp)
      apply(rename_tac k', case_tac k', simp)
      apply(rename_tac k'', case_tac k'', simp)
      apply(rename_tac k''', case_tac k''', simp_all)
      apply(rule arg_cong[where f=Old_Datatype.Lim])
      apply(rule ext)
      apply(simp add: IH)
      done
  qed
qed

lemma Eq_RESUMPTION_refl:
  assumes "r ∈ resumption"
  shows "Eq_RESUMPTION r r"
proof -
  define r' where "r' = r"
  with assms have "r = r' ∧ r ∈ resumption" by auto
  thus "Eq_RESUMPTION r r'"
  proof(coinduct)
    case (Eq_RESUMPTION r r')
    hence [simp]: "r = r'" and "r ∈ resumption" by auto
    from ‹r ∈ resumption› show ?case
      by(cases rule: resumption.cases) auto
  qed
qed

lemma Eq_RESUMPTION_into_resumption:
  assumes "Eq_RESUMPTION r r"
  shows "r ∈ resumption"
using assms
proof(coinduct)
  case resumption thus ?case by cases auto
qed

lemma Eq_RESUMPTION_eq:
  "Eq_RESUMPTION r r' ⟷ r = r' ∧ r ∈ resumption"
proof(rule iffI)
  assume "Eq_RESUMPTION r r'"
  hence "⋀k. ntrunc k r = ntrunc k r'" by(rule Eq_RESUMPTION_implies_ntrunc_equality)
  hence "r = r'" by(rule ntrunc_equality)
  moreover with ‹Eq_RESUMPTION r r'› have "r ∈ resumption"
    by(auto intro: Eq_RESUMPTION_into_resumption)
  ultimately show "r = r' ∧ r ∈ resumption" ..
next
  assume "r = r' ∧ r ∈ resumption"
  thus "Eq_RESUMPTION r r'" by(blast intro: Eq_RESUMPTION_refl)
qed

lemma Eq_RESUMPTION_I [consumes 1, case_names Eq_RESUMPTION, case_conclusion Eq_RESUMPTION EqTerminal EqLinear EqBranch]:
  assumes "X r r'"
  and step: "⋀r r'. X r r' ⟹
             (∃a. r = TERMINAL a ∧ r' = TERMINAL a) ∨
             (∃R R' b. r = LINEAR b R ∧ r' = LINEAR b R' ∧ (X R R' ∨ Eq_RESUMPTION R R')) ∨
             (∃rs rs' c. r = BRANCH c rs ∧ r' = BRANCH c rs' ∧ (∀d. X (rs d) (rs' d) ∨ Eq_RESUMPTION (rs d) (rs' d)))"
  shows "r = r'"
proof -
  from ‹X r r'› have "Eq_RESUMPTION r r'"
    by(coinduct)(rule step)
  thus ?thesis by(simp add: Eq_RESUMPTION_eq)
qed

lemma resumption_equalityI [consumes 1, case_names Eq_resumption, case_conclusion Eq_resumption EqTerminal EqLinear EqBranch]:
  assumes "X r r'"
  and step: "⋀r r'. X r r' ⟹
             (∃a. r = Terminal a ∧ r' = Terminal a) ∨
             (∃R R' b. r = Linear b R ∧ r' = Linear b R' ∧ (X R R' ∨ R = R')) ∨
             (∃rs rs' c. r = Branch c rs ∧ r' = Branch c rs' ∧ (∀d. X (rs d) (rs' d) ∨ rs d = rs' d))"
  shows "r = r'"
proof -
  define M N where "M = Rep_resumption r" and "N = Rep_resumption r'"
  with ‹X r r'› have "∃r r'. M = Rep_resumption r ∧ N = Rep_resumption r' ∧ X r r'" by blast
  hence "M = N"
  proof(coinduct rule: Eq_RESUMPTION_I)
    case (Eq_RESUMPTION M N)
    then obtain r r' where [simp]: "M = Rep_resumption r" "N = Rep_resumption r'"
      and "X r r'" by blast
    { assume "∃a. r = Terminal a ∧ r' = Terminal a"
      hence ?EqTerminal by(auto simp add: Rep_resumption_constructors)
      hence ?case .. }
    moreover
    { assume "∃R R' b. r = Linear b R ∧ r' = Linear b R' ∧ (X R R' ∨ R = R')"
      hence ?EqLinear
        by(clarsimp simp add: Rep_resumption_constructors Eq_RESUMPTION_eq Rep_resumption_inject Rep_resumption)
      hence ?case by blast }
    moreover
    { assume "∃rs rs' c. r = Branch c rs ∧ r' = Branch c rs' ∧ (∀d. X (rs d) (rs' d) ∨ rs d = rs' d)"
      hence ?EqBranch
        by(clarsimp simp add: Rep_resumption_constructors Eq_RESUMPTION_eq Rep_resumption_inject Rep_resumption)
      hence ?case by blast }
    ultimately show ?case using step[OF ‹X r r'›] by blast
  qed
  thus ?thesis unfolding M_def N_def by(simp add: Rep_resumption_inject)
qed

text ‹
  Finality of ‹resumption›: Uniqueness of functions defined by corecursion.
›

lemma equals_RESUMPTION_corec:
  assumes h: "⋀x. h x = (case f x of Terminal_corec a ⇒ TERMINAL a
                                   | Linear_corec b x' ⇒ LINEAR b (h x')
                                   | Branch_corec c xs ⇒ BRANCH c (λd. h (xs d))
                                   | Resumption_corec r ⇒ Rep_resumption r)"
  shows "h = RESUMPTION_corec f"
proof
  fix x
  define h' where "h' = RESUMPTION_corec f"
  have h': "⋀x. h' x = (case f x of Terminal_corec a ⇒ TERMINAL a
                                   | Linear_corec b x' ⇒ LINEAR b (h' x')
                                   | Branch_corec c xs ⇒ BRANCH c (λd. h' (xs d))
                                   | Resumption_corec r ⇒ Rep_resumption r)"
    unfolding h'_def by(simp add: RESUMPTION_corec)
  define M N where "M = h x" and "N = h' x"
  hence "∃x. M = h x ∧ N = h' x" by blast
  thus "M = N"
  proof(coinduct rule: Eq_RESUMPTION_I)
    case (Eq_RESUMPTION M N)
    then obtain x where [simp]: "M = h x" "N = h' x" by blast
    show ?case
    proof(cases "f x")
      case (Terminal_corec a)
      with h h' have ?EqTerminal by simp
      thus ?thesis ..
    next
      case (Linear_corec b x')
      with h h' have ?EqLinear by auto
      thus ?thesis by blast
    next
      case (Branch_corec c xs)
      with h h' have ?EqBranch by auto
      thus ?thesis by blast
    next
      case (Resumption_corec r)
      thus ?thesis
        by(cases r)(simp_all add: h h' Rep_resumption_constructors Eq_RESUMPTION_refl Rep_resumption)
    qed
  qed
qed

lemma equals_resumption_corec:
  assumes h: "⋀x. h x = (case f x of Terminal_corec a ⇒ Terminal a
                                   | Linear_corec b x' ⇒ Linear b (h x')
                                   | Branch_corec c xs ⇒ Branch c (λd. h (xs d))
                                   | Resumption_corec r ⇒ r)"
  shows "h = resumption_corec f"
proof(rule ext)
  fix x
  { fix x
    from h[of x]
    have "Rep_resumption (h x) =
      (case f x of Terminal_corec a ⇒ TERMINAL a
                | Linear_corec b x' ⇒ LINEAR b (Rep_resumption (h x'))
                | Branch_corec c xs ⇒ BRANCH c (λd. Rep_resumption (h (xs d)))
                | Resumption_corec r ⇒ Rep_resumption r)"
      by(auto split: resumption_corec.split simp add: Rep_resumption_constructors) }
  hence eq: "(λx. Rep_resumption (h x)) = RESUMPTION_corec f" by(rule equals_RESUMPTION_corec)
  hence "Abs_resumption (Rep_resumption (h x)) = Abs_resumption (RESUMPTION_corec f x)"
    by(subst (asm) fun_eq_iff)(auto)
  from this[symmetric] show "h x = resumption_corec f x"
    unfolding resumption_corec_def by(simp add: Rep_resumption_inverse)
qed

end