src/HOL/Library/AList.thy
changeset 60500 903bb1495239
parent 60043 177d740a0d48
child 61585 a9599d3d7610
equal deleted inserted replaced
60499:54a3db2ed201 60500:903bb1495239
     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]:
   378 
   378 
   379 lemma restr_delete_twist: "(restrict A (delete a ps)) = delete a (restrict A ps)"
   379 lemma restr_delete_twist: "(restrict A (delete a ps)) = delete a (restrict A ps)"
   380   by (induct ps) auto
   380   by (induct ps) auto
   381 
   381 
   382 
   382 
   383 subsection {* @{text clearjunk} *}
   383 subsection \<open>@{text clearjunk}\<close>
   384 
   384 
   385 qualified function clearjunk  :: "('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list"
   385 qualified function clearjunk  :: "('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list"
   386 where
   386 where
   387   "clearjunk [] = []"
   387   "clearjunk [] = []"
   388 | "clearjunk (p#ps) = p # clearjunk (delete (fst p) ps)"
   388 | "clearjunk (p#ps) = p # clearjunk (delete (fst p) ps)"
   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) =