1 (* Title: HOL/Library/AList.thy |
1 (* Title: HOL/Library/AList.thy |
2 Author: Norbert Schirmer, Tobias Nipkow, Martin Wildmoser, TU Muenchen |
2 Author: Norbert Schirmer, Tobias Nipkow, Martin Wildmoser, TU Muenchen |
3 *) |
3 *) |
4 |
4 |
5 section {* Implementation of Association Lists *} |
5 section \<open>Implementation of Association Lists\<close> |
6 |
6 |
7 theory AList |
7 theory AList |
8 imports Main |
8 imports Main |
9 begin |
9 begin |
10 |
10 |
11 context |
11 context |
12 begin |
12 begin |
13 |
13 |
14 text {* |
14 text \<open> |
15 The operations preserve distinctness of keys and |
15 The operations preserve distinctness of keys and |
16 function @{term "clearjunk"} distributes over them. Since |
16 function @{term "clearjunk"} distributes over them. Since |
17 @{term clearjunk} enforces distinctness of keys it can be used |
17 @{term clearjunk} enforces distinctness of keys it can be used |
18 to establish the invariant, e.g. for inductive proofs. |
18 to establish the invariant, e.g. for inductive proofs. |
19 *} |
19 \<close> |
20 |
20 |
21 subsection {* @{text update} and @{text updates} *} |
21 subsection \<open>@{text update} and @{text updates}\<close> |
22 |
22 |
23 qualified primrec update :: "'key \<Rightarrow> 'val \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
23 qualified primrec update :: "'key \<Rightarrow> 'val \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
24 where |
24 where |
25 "update k v [] = [(k, v)]" |
25 "update k v [] = [(k, v)]" |
26 | "update k v (p # ps) = (if fst p = k then (k, v) # ps else p # update k v ps)" |
26 | "update k v (p # ps) = (if fst p = k then (k, v) # ps else p # update k v ps)" |
66 qed |
66 qed |
67 |
67 |
68 lemma update_last [simp]: "update k v (update k v' al) = update k v al" |
68 lemma update_last [simp]: "update k v (update k v' al) = update k v al" |
69 by (induct al) auto |
69 by (induct al) auto |
70 |
70 |
71 text {* Note that the lists are not necessarily the same: |
71 text \<open>Note that the lists are not necessarily the same: |
72 @{term "update k v (update k' v' []) = [(k', v'), (k, v)]"} and |
72 @{term "update k v (update k' v' []) = [(k', v'), (k, v)]"} and |
73 @{term "update k' v' (update k v []) = [(k, v), (k', v')]"}.*} |
73 @{term "update k' v' (update k v []) = [(k, v), (k', v')]"}.\<close> |
74 |
74 |
75 lemma update_swap: |
75 lemma update_swap: |
76 "k \<noteq> k' \<Longrightarrow> |
76 "k \<noteq> k' \<Longrightarrow> |
77 map_of (update k v (update k' v' al)) = map_of (update k' v' (update k v al))" |
77 map_of (update k v (update k' v' al)) = map_of (update k' v' (update k v al))" |
78 by (simp add: update_conv' fun_eq_iff) |
78 by (simp add: update_conv' fun_eq_iff) |
161 lemma updates_append2_drop [simp]: |
161 lemma updates_append2_drop [simp]: |
162 "size xs = size ys \<Longrightarrow> updates xs (ys @ zs) al = updates xs ys al" |
162 "size xs = size ys \<Longrightarrow> updates xs (ys @ zs) al = updates xs ys al" |
163 by (induct xs arbitrary: ys al) (auto split: list.splits) |
163 by (induct xs arbitrary: ys al) (auto split: list.splits) |
164 |
164 |
165 |
165 |
166 subsection {* @{text delete} *} |
166 subsection \<open>@{text delete}\<close> |
167 |
167 |
168 qualified definition delete :: "'key \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
168 qualified definition delete :: "'key \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
169 where delete_eq: "delete k = filter (\<lambda>(k', _). k \<noteq> k')" |
169 where delete_eq: "delete k = filter (\<lambda>(k', _). k \<noteq> k')" |
170 |
170 |
171 lemma delete_simps [simp]: |
171 lemma delete_simps [simp]: |
213 |
213 |
214 lemma length_delete_le: "length (delete k al) \<le> length al" |
214 lemma length_delete_le: "length (delete k al) \<le> length al" |
215 by (simp add: delete_eq) |
215 by (simp add: delete_eq) |
216 |
216 |
217 |
217 |
218 subsection {* @{text update_with_aux} and @{text delete_aux}*} |
218 subsection \<open>@{text update_with_aux} and @{text delete_aux}\<close> |
219 |
219 |
220 qualified primrec update_with_aux :: "'val \<Rightarrow> 'key \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
220 qualified primrec update_with_aux :: "'val \<Rightarrow> 'key \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
221 where |
221 where |
222 "update_with_aux v k f [] = [(k, f v)]" |
222 "update_with_aux v k f [] = [(k, f v)]" |
223 | "update_with_aux v k f (p # ps) = (if (fst p = k) then (k, f (snd p)) # ps else p # update_with_aux v k f ps)" |
223 | "update_with_aux v k f (p # ps) = (if (fst p = k) then (k, f (snd p)) # ps else p # update_with_aux v k f ps)" |
224 |
224 |
225 text {* |
225 text \<open> |
226 The above @{term "delete"} traverses all the list even if it has found the key. |
226 The above @{term "delete"} traverses all the list even if it has found the key. |
227 This one does not have to keep going because is assumes the invariant that keys are distinct. |
227 This one does not have to keep going because is assumes the invariant that keys are distinct. |
228 *} |
228 \<close> |
229 qualified fun delete_aux :: "'key \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
229 qualified fun delete_aux :: "'key \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
230 where |
230 where |
231 "delete_aux k [] = []" |
231 "delete_aux k [] = []" |
232 | "delete_aux k ((k', v) # xs) = (if k = k' then xs else (k', v) # delete_aux k xs)" |
232 | "delete_aux k ((k', v) # xs) = (if k = k' then xs else (k', v) # delete_aux k xs)" |
233 |
233 |
294 |
294 |
295 lemma delete_aux_eq_Nil_conv: "delete_aux k ts = [] \<longleftrightarrow> ts = [] \<or> (\<exists>v. ts = [(k, v)])" |
295 lemma delete_aux_eq_Nil_conv: "delete_aux k ts = [] \<longleftrightarrow> ts = [] \<or> (\<exists>v. ts = [(k, v)])" |
296 by(cases ts)(auto split: split_if_asm) |
296 by(cases ts)(auto split: split_if_asm) |
297 |
297 |
298 |
298 |
299 subsection {* @{text restrict} *} |
299 subsection \<open>@{text restrict}\<close> |
300 |
300 |
301 qualified definition restrict :: "'key set \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
301 qualified definition restrict :: "'key set \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
302 where restrict_eq: "restrict A = filter (\<lambda>(k, v). k \<in> A)" |
302 where restrict_eq: "restrict A = filter (\<lambda>(k, v). k \<in> A)" |
303 |
303 |
304 lemma restr_simps [simp]: |
304 lemma restr_simps [simp]: |
462 shows "clearjunk (map f ps) = map f (clearjunk ps)" |
462 shows "clearjunk (map f ps) = map f (clearjunk ps)" |
463 by (induct ps rule: clearjunk.induct [case_names Nil Cons]) |
463 by (induct ps rule: clearjunk.induct [case_names Nil Cons]) |
464 (simp_all add: clearjunk_delete delete_map assms) |
464 (simp_all add: clearjunk_delete delete_map assms) |
465 |
465 |
466 |
466 |
467 subsection {* @{text map_ran} *} |
467 subsection \<open>@{text map_ran}\<close> |
468 |
468 |
469 definition map_ran :: "('key \<Rightarrow> 'val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
469 definition map_ran :: "('key \<Rightarrow> 'val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
470 where "map_ran f = map (\<lambda>(k, v). (k, f k v))" |
470 where "map_ran f = map (\<lambda>(k, v). (k, f k v))" |
471 |
471 |
472 lemma map_ran_simps [simp]: |
472 lemma map_ran_simps [simp]: |
488 |
488 |
489 lemma clearjunk_map_ran: "clearjunk (map_ran f al) = map_ran f (clearjunk al)" |
489 lemma clearjunk_map_ran: "clearjunk (map_ran f al) = map_ran f (clearjunk al)" |
490 by (simp add: map_ran_def split_def clearjunk_map) |
490 by (simp add: map_ran_def split_def clearjunk_map) |
491 |
491 |
492 |
492 |
493 subsection {* @{text merge} *} |
493 subsection \<open>@{text merge}\<close> |
494 |
494 |
495 qualified definition merge :: "('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
495 qualified definition merge :: "('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
496 where "merge qs ps = foldr (\<lambda>(k, v). update k v) ps qs" |
496 where "merge qs ps = foldr (\<lambda>(k, v). update k v) ps qs" |
497 |
497 |
498 lemma merge_simps [simp]: |
498 lemma merge_simps [simp]: |
556 |
556 |
557 lemma merge_append: "map_of (xs @ ys) = map_of (merge ys xs)" |
557 lemma merge_append: "map_of (xs @ ys) = map_of (merge ys xs)" |
558 by (simp add: merge_conv') |
558 by (simp add: merge_conv') |
559 |
559 |
560 |
560 |
561 subsection {* @{text compose} *} |
561 subsection \<open>@{text compose}\<close> |
562 |
562 |
563 qualified function compose :: "('key \<times> 'a) list \<Rightarrow> ('a \<times> 'b) list \<Rightarrow> ('key \<times> 'b) list" |
563 qualified function compose :: "('key \<times> 'a) list \<Rightarrow> ('a \<times> 'b) list \<Rightarrow> ('key \<times> 'b) list" |
564 where |
564 where |
565 "compose [] ys = []" |
565 "compose [] ys = []" |
566 | "compose (x # xs) ys = |
566 | "compose (x # xs) ys = |
721 "map_of (compose xs ys) k = None \<longleftrightarrow> |
721 "map_of (compose xs ys) k = None \<longleftrightarrow> |
722 (map_of xs k = None \<or> (\<exists>k'. map_of xs k = Some k' \<and> map_of ys k' = None))" |
722 (map_of xs k = None \<or> (\<exists>k'. map_of xs k = Some k' \<and> map_of ys k' = None))" |
723 by (simp add: compose_conv map_comp_None_iff) |
723 by (simp add: compose_conv map_comp_None_iff) |
724 |
724 |
725 |
725 |
726 subsection {* @{text map_entry} *} |
726 subsection \<open>@{text map_entry}\<close> |
727 |
727 |
728 qualified fun map_entry :: "'key \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
728 qualified fun map_entry :: "'key \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
729 where |
729 where |
730 "map_entry k f [] = []" |
730 "map_entry k f [] = []" |
731 | "map_entry k f (p # ps) = |
731 | "map_entry k f (p # ps) = |
743 assumes "distinct (map fst xs)" |
743 assumes "distinct (map fst xs)" |
744 shows "distinct (map fst (map_entry k f xs))" |
744 shows "distinct (map fst (map_entry k f xs))" |
745 using assms by (induct xs) (auto simp add: dom_map_entry) |
745 using assms by (induct xs) (auto simp add: dom_map_entry) |
746 |
746 |
747 |
747 |
748 subsection {* @{text map_default} *} |
748 subsection \<open>@{text map_default}\<close> |
749 |
749 |
750 fun map_default :: "'key \<Rightarrow> 'val \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
750 fun map_default :: "'key \<Rightarrow> 'val \<Rightarrow> ('val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list" |
751 where |
751 where |
752 "map_default k v f [] = [(k, v)]" |
752 "map_default k v f [] = [(k, v)]" |
753 | "map_default k v f (p # ps) = |
753 | "map_default k v f (p # ps) = |