(* Author: Andreas Lochbihler, ETH Zurich
Author: Peter Gammie *)
section‹A codatatype of infinite binary trees›
theory Cotree imports
Main
Applicative_Lifting.Applicative "HOL-Library.BNF_Corec" begin
contextnotes [[bnf_internals]] begin
codatatype 'a tree = Node (root: 'a) (left: "'a tree") (right: "'a tree") end
lemma rel_treeD: assumes"rel_tree A x y" shows rel_tree_rootD: "A (root x) (root y)" and rel_tree_leftD: "rel_tree A (left x) (left y)" and rel_tree_rightD: "rel_tree A (right x) (right y)" using assms by(cases x y rule: tree.exhaust[case_product tree.exhaust], simp_all)+
lemmas [simp] = tree.map_sel tree.map_comp
lemma set_tree_induct[consumes 1, case_names root left right]: assumes x: "x ∈ set_tree t" and root: "∧t. P (root t) t" and left: "∧x t. [ x ∈ set_tree (left t); P x (left t) ]==> P x t" and right: "∧x t. [ x ∈ set_tree (right t); P x (right t) ]==> P x t" shows"P x t" using x proof(rule tree.set_induct) fix l x r from root[of "Node x l r"] show"P x (Node x l r)"by simp qed(auto intro: left right)
lemma corec_tree_cong: assumes"∧x. stopL x ==> STOPL x = STOPL' x" and"∧x. ~ stopL x ==> LEFT x = LEFT' x" and"∧x. stopR x ==> STOPR x = STOPR' x" and"∧x. ¬ stopR x ==> RIGHT x = RIGHT' x" shows"corec_tree ROOT stopL STOPL LEFT stopR STOPR RIGHT = corec_tree ROOT stopL STOPL' LEFT' stopR STOPR' RIGHT'"
(is"?lhs = ?rhs") proof fix x show"?lhs x = ?rhs x" by(coinduction arbitrary: x rule: tree.coinduct_strong)(auto simp add: assms) qed
context fixes g1 :: "'a ==> 'b" and g22 :: "'a ==> 'a" and g32 :: "'a ==> 'a" begin
corec unfold_tree :: "'a ==> 'b tree" where"unfold_tree a = Node (g1 a) (unfold_tree (g22 a)) (unfold_tree (g32 a))"
lemma unfold_tree_simps [simp]: "root (unfold_tree a) = g1 a" "left (unfold_tree a) = unfold_tree (g22 a)" "right (unfold_tree a) = unfold_tree (g32 a)" by(subst unfold_tree.code; simp; fail)+
end
lemma unfold_tree_unique: assumes"∧s. root (f s) = ROOT s" and"∧s. left (f s) = f (LEFT s)" and"∧s. right (f s) = f (RIGHT s)" shows"f s = unfold_tree ROOT LEFT RIGHT s" by(rule unfold_tree.unique[THEN fun_cong])(auto simp add: fun_eq_iff assms intro: tree.expand)
subsection‹Applicative functor for @{typ "'a tree"}›
contextfixes x :: "'a"begin
corec pure_tree :: "'a tree" where"pure_tree = Node x pure_tree pure_tree" end
lemma ap_tree_strong_extensional: "(∧x. f ♢ pure x = g ♢ pure x) ==> f = g" proof(coinduction arbitrary: f g) case [rule_format]: (Eq_tree f g) have"root f = root g" proof fix x show"root f x = root g x" using Eq_tree[of x] by(subst (asm) (12) ap_tree.ctr) simp qed moreover { fix x have"left f ♢ pure x = left g ♢ pure x" using Eq_tree[of x] by(subst (asm) (12) ap_tree.ctr) simp
} moreover { fix x have"right f ♢ pure x = right g ♢ pure x" using Eq_tree[of x] by(subst (asm) (12) ap_tree.ctr) simp
} ultimatelyshow ?caseby simp qed
lemma ap_tree_extensional: "(∧x. f ♢ x = g ♢ x) ==> f = g" by(rule ap_tree_strong_extensional) simp
subsection‹Standard tree combinators›
subsubsection‹Recurse combinator›
text‹
This will be the main combinator to define trees recursively
Uniqueness for this gives us the unique fixed-point theorem for guarded recursive definitions. › lemma map_unfold_tree [simp]: fixes l r x defines"unf ≡ unfold_tree (λf. f x) (λf. f ∘ l) (λf. f ∘ r)" shows"map_tree G (unf F) = unf (G ∘ F)" by(coinduction arbitrary: F G)(auto 43 simp add: unf_def o_assoc)
friend_of_corec map_tree :: "('a ==> 'a) ==> 'a tree ==> 'a tree"where "map_tree f t = Node (f (root t)) (map_tree f (left t)) (map_tree f (right t))"
subgoal by (rule tree.expand; simp)
subgoal by (fold relator_eq; transfer_prover) done
contextfixes l :: "'a ==> 'a"and r :: "'a ==> 'a"and x :: "'a"begin
corec tree_recurse :: "'a tree" where"tree_recurse = Node x (map_tree l tree_recurse) (map_tree r tree_recurse)" end
lemma tree_recurse_simps [simp]: "root (tree_recurse l r x) = x" "left (tree_recurse l r x) = map_tree l (tree_recurse l r x)" "right (tree_recurse l r x) = map_tree r (tree_recurse l r x)" by(subst tree_recurse.code; simp; fail)+
lemma tree_recurse_unfold: "tree_recurse l r x = Node x (map_tree l (tree_recurse l r x)) (map_tree r (tree_recurse l r x))" by(fact tree_recurse.code)
lemma tree_recurse_fusion: assumes"h ∘ l = l' ∘ h"and"h ∘ r = r' ∘ h" shows"map_tree h (tree_recurse l r x) = tree_recurse l' r' (h x)" by(rule tree_recurse.unique)(simp add: tree.expand assms)
subsubsection‹Tree iteration›
contextfixes l :: "'a ==> 'a"and r :: "'a ==> 'a"begin
primcorec tree_iterate :: " 'a ==> 'a tree" where"tree_iterate s = Node s (tree_iterate (l s)) (tree_iterate (r s))" end
lemma unfold_tree_tree_iterate: "unfold_tree out l r = map_tree out ∘ tree_iterate l r" by(rule ext)(rule unfold_tree_unique[symmetric]; simp)
lemma tree_iterate_fusion: assumes"h ∘ l = l' ∘ h" assumes"h ∘ r = r' ∘ h" shows"map_tree h (tree_iterate l r x) = tree_iterate l' r' (h x)" apply(coinduction arbitrary: x) using assms by(auto simp add: fun_eq_iff)
subsubsection‹Tree traversal›
datatype dir = L | R type_synonym path = "dir list"
definition traverse_tree :: "path ==> 'a tree ==> 'a tree" where"traverse_tree path ≡ foldr (λd f. f ∘ case_dir left right d) path id"
lemma traverse_tree_simps[simp]: "traverse_tree [] = id" "traverse_tree (d # path) = traverse_tree path ∘ (case d of L ==> left | R ==> right)" by (simp_all add: traverse_tree_def)
lemma traverse_tree_map_tree [simp]: "traverse_tree path (map_tree f t) = map_tree f (traverse_tree path t)" by (induct path arbitrary: t) (simp_all split: dir.splits)
lemma traverse_tree_append [simp]: "traverse_tree (path @ ext) t = traverse_tree ext (traverse_tree path t)" by (induct path arbitrary: t) simp_all
text‹@{const "traverse_tree"} is an applicative-functor homomorphism.›
lemma traverse_tree_pure_tree [simp]: "traverse_tree path (pure x) = pure x" by (induct path arbitrary: x) (simp_all split: dir.splits)
lemma traverse_tree_ap [simp]: "traverse_tree path (f ♢ x) = traverse_tree path f ♢ traverse_tree path x" by (induct path arbitrary: f x) (simp_all split: dir.splits)
contextfixes l r :: "'a ==> 'a"begin
primrec traverse_dir :: "dir ==> 'a ==> 'a" where "traverse_dir L = l"
| "traverse_dir R = r"
lemma traverse_tree_tree_iterate: "traverse_tree path (tree_iterate l r s) = tree_iterate l r (traverse_path l r path s)" by (induct path arbitrary: s) (simp_all split: dir.splits)
text‹
citeauthor{DBLP:journals/jfp/Hinze09} shows that if the tree
function is suitably monoidal then recursion and
define the same tree.
›
lemma tree_recurse_iterate: assumes monoid: "∧x y z. f (f x y) z = f x (f y z)" "∧x. f x ε = x" "∧x. f ε x = x" shows"tree_recurse (f l) (f r) ε = tree_iterate (λx. f x l) (λx. f x r) ε" apply(rule tree_recurse.unique[symmetric]) apply(rule tree.expand) apply(simp add: tree_iterate_fusion[where r'="λx. f x r"and l'="λx. f x l"] fun_eq_iff monoid) done
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.