Theory Resumption
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 [code del]:
"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›