# HG changeset patch # User Andreas Lochbihler # Date 1531722747 -7200 # Node ID 4a2b72b082dc12912be019c01a667e6b44c160e1 # Parent 87d1bff264df0c7edeb73f3df4dd7f641cfd73c0# Parent f15daa73ee326e370965dbf7f9d1e895394e9523 merged diff -r 87d1bff264df -r 4a2b72b082dc NEWS --- a/NEWS Sun Jul 15 21:58:50 2018 +0100 +++ b/NEWS Mon Jul 16 08:32:27 2018 +0200 @@ -379,8 +379,9 @@ * Theory HOL-Library.Code_Lazy provides a new preprocessor for the code generator to generate code for algebraic types with lazy evaluation -semantics even in call-by-value target languages. See theory -HOL-Codegenerator_Test.Code_Lazy_Test for some examples. +semantics even in call-by-value target languages. See the theories +HOL-ex.Code_Lazy_Demo and HOL-Codegenerator_Test.Code_Lazy_Test for +some examples. * Theory HOL-Library.Landau_Symbols has been moved here from AFP. diff -r 87d1bff264df -r 4a2b72b082dc src/HOL/ROOT --- a/src/HOL/ROOT Sun Jul 15 21:58:50 2018 +0100 +++ b/src/HOL/ROOT Mon Jul 16 08:32:27 2018 +0200 @@ -542,6 +542,7 @@ Chinese Classical Code_Binary_Nat_examples + Code_Lazy_Demo Code_Timing Coercion_Examples Coherent diff -r 87d1bff264df -r 4a2b72b082dc src/HOL/ex/Code_Lazy_Demo.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/ex/Code_Lazy_Demo.thy Mon Jul 16 08:32:27 2018 +0200 @@ -0,0 +1,178 @@ +(* Author: Andreas Lochbihler, Digital Asset *) + +theory Code_Lazy_Demo imports + "HOL-Library.Code_Lazy" + "HOL-Library.Debug" + "HOL-Library.RBT_Impl" +begin + +text \This theory demonstrates the use of the @{theory "HOL-Library.Code_Lazy"} theory.\ + +section \Streams\ + +text \Lazy evaluation for streams\ + +codatatype 'a stream = + SCons (shd: 'a) (stl: "'a stream") (infixr "##" 65) + +primcorec up :: "nat \ nat stream" where + "up n = n ## up (n + 1)" + +primrec stake :: "nat \ 'a stream \ 'a list" where + "stake 0 xs = []" +| "stake (Suc n) xs = shd xs # stake n (stl xs)" + +code_thms up stake \ \The original code equations\ + +code_lazy_type stream + +code_thms up stake \ \The lazified code equations\ + +value "stake 5 (up 3)" + + +section \Finite lazy lists\ + +text \Lazy types need not be infinite. We can also have lazy types that are finite.\ + +datatype 'a llist + = LNil ("\<^bold>\\<^bold>\") + | LCons (lhd: 'a) (ltl: "'a llist") (infixr "###" 65) + +syntax "_llist" :: "args => 'a list" ("\<^bold>\(_)\<^bold>\") +translations + "\<^bold>\x, xs\<^bold>\" == "x###\<^bold>\xs\<^bold>\" + "\<^bold>\x\<^bold>\" == "x###\<^bold>\\<^bold>\" + +fun lnth :: "nat \ 'a llist \ 'a" where + "lnth 0 (x ### xs) = x" +| "lnth (Suc n) (x ### xs) = lnth n xs" + +definition llist :: "nat llist" where + "llist = \<^bold>\1, 2, 3, hd [], 4\<^bold>\" + +code_lazy_type llist + +value [code] "llist" +value [code] "lnth 2 llist" +value [code] "let x = lnth 2 llist in (x, llist)" + +fun lfilter :: "('a \ bool) \ 'a llist \ 'a llist" where + "lfilter P \<^bold>\\<^bold>\ = \<^bold>\\<^bold>\" +| "lfilter P (x ### xs) = + (if P x then x ### lfilter P xs else lfilter P xs)" + +export_code lfilter in SML + +value [code] "lfilter odd llist" + +value [code] "lhd (lfilter odd llist)" + + +section \Iterator for red-black trees\ + +text \Thanks to laziness, we do not need to program a complicated iterator for a tree. + A conversion function to lazy lists is enough.\ + +primrec lappend :: "'a llist \ 'a llist \ 'a llist" + (infixr "@@" 65) where + "\<^bold>\\<^bold>\ @@ ys = ys" +| "(x ### xs) @@ ys = x ### (xs @@ ys)" + +primrec rbt_iterator :: "('a, 'b) rbt \ ('a \ 'b) llist" where + "rbt_iterator rbt.Empty = \<^bold>\\<^bold>\" +| "rbt_iterator (Branch _ l k v r) = + (let _ = Debug.flush (STR ''tick'') in + rbt_iterator l @@ (k, v) ### rbt_iterator r)" + +definition tree :: "(nat, unit) rbt" + where "tree = fold (\k. rbt_insert k ()) [0..<100] rbt.Empty" + +definition find_min :: "('a :: linorder, 'b) rbt \ ('a \ 'b) option" where + "find_min rbt = + (case rbt_iterator rbt of \<^bold>\\<^bold>\ \ None + | kv ### _ \ Some kv)" + +value "find_min tree" \ \Observe that @{const rbt_iterator} is evaluated only for going down + to the first leaf, not for the whole tree (as seen by the ticks).\ + +text \With strict lists, the whole tree is converted into a list.\ + +deactivate_lazy_type llist +value "find_min tree" +activate_lazy_type llist + + + +section \Branching datatypes\ + +datatype tree + = L ("\") + | Node tree tree (infix "\" 900) + +notation (output) Node ("\(//\<^bold>l: _//\<^bold>r: _)") + +code_lazy_type tree + +fun mk_tree :: "nat \ tree" where mk_tree_0: + "mk_tree 0 = \" +| "mk_tree (Suc n) = (let t = mk_tree n in t \ t)" + +declare mk_tree.simps [code] + +code_thms mk_tree + +function subtree :: "bool list \ tree \ tree" where + "subtree [] t = t" +| "subtree (True # p) (l \ r) = subtree p l" +| "subtree (False # p) (l \ r) = subtree p r" +| "subtree _ \ = \" + by pat_completeness auto +termination by lexicographic_order + +value [code] "mk_tree 10" +value [code] "let t = mk_tree 10; _ = subtree [True, True, False, False] t in t" + \ \Since @{const mk_tree} shares the two subtrees of a node thanks to the let binding, + digging into one subtree spreads to the whole tree.\ +value [code] "let t = mk_tree 3; _ = subtree [True, True, False, False] t in t" + +lemma mk_tree_Suc_debug [code]: \ \Make the evaluation visible with tracing.\ + "mk_tree (Suc n) = + (let _ = Debug.flush (STR ''tick''); t = mk_tree n in t \ t)" + by simp + +value [code] "mk_tree 10" + \ \The recursive call to @{const mk_tree} is not guarded by a lazy constructor, + so all the suspensions are built up immediately.\ + +lemma mk_tree_Suc [code]: "mk_tree (Suc n) = mk_tree n \ mk_tree n" + \ \In this code equation, there is no sharing and the recursive calls are guarded by a constructor.\ + by(simp add: Let_def) + +value [code] "mk_tree 10" +value [code] "let t = mk_tree 10; _ = subtree [True, True, False, False] t in t" + +lemma mk_tree_Suc_debug' [code]: + "mk_tree (Suc n) = (let _ = Debug.flush (STR ''tick'') in mk_tree n \ mk_tree n)" + by(simp add: Let_def) + +value [code] "mk_tree 10" \ \Only one tick thanks to the guarding constructor\ +value [code] "let t = mk_tree 10; _ = subtree [True, True, False, False] t in t" +value [code] "let t = mk_tree 3; _ = subtree [True, True, False, False] t in t" + + +section \Pattern matching elimination\ + +text \The pattern matching elimination handles deep pattern matches and overlapping equations + and only eliminates necessary pattern matches.\ + +function crazy :: "nat llist llist \ tree \ bool \ unit" where + "crazy (\<^bold>\0\<^bold>\ ### xs) _ _ = Debug.flush (1 :: integer)" +| "crazy xs \ True = Debug.flush (2 :: integer)" +| "crazy xs t b = Debug.flush (3 :: integer)" + by pat_completeness auto +termination by lexicographic_order + +code_thms crazy + +end \ No newline at end of file