17 association list of subtries. This is an example of nested recursion involving products, |
17 association list of subtries. This is an example of nested recursion involving products, |
18 which is fine because products are datatypes as well. |
18 which is fine because products are datatypes as well. |
19 We define two selector functions: |
19 We define two selector functions: |
20 *}; |
20 *}; |
21 |
21 |
22 consts "value" :: "('a,'v)trie \<Rightarrow> 'v option" |
22 primrec "value" :: "('a,'v)trie \<Rightarrow> 'v option" where |
23 alist :: "('a,'v)trie \<Rightarrow> ('a * ('a,'v)trie)list"; |
23 "value(Trie ov al) = ov" |
24 primrec "value(Trie ov al) = ov"; |
24 primrec alist :: "('a,'v)trie \<Rightarrow> ('a * ('a,'v)trie)list" where |
25 primrec "alist(Trie ov al) = al"; |
25 "alist(Trie ov al) = al" |
26 |
26 |
27 text{*\noindent |
27 text{*\noindent |
28 Association lists come with a generic lookup function. Its result |
28 Association lists come with a generic lookup function. Its result |
29 involves type @{text option} because a lookup can fail: |
29 involves type @{text option} because a lookup can fail: |
30 *}; |
30 *}; |
31 |
31 |
32 consts assoc :: "('key * 'val)list \<Rightarrow> 'key \<Rightarrow> 'val option"; |
32 primrec assoc :: "('key * 'val)list \<Rightarrow> 'key \<Rightarrow> 'val option" where |
33 primrec "assoc [] x = None" |
33 "assoc [] x = None" | |
34 "assoc (p#ps) x = |
34 "assoc (p#ps) x = |
35 (let (a,b) = p in if a=x then Some b else assoc ps x)"; |
35 (let (a,b) = p in if a=x then Some b else assoc ps x)" |
36 |
36 |
37 text{* |
37 text{* |
38 Now we can define the lookup function for tries. It descends into the trie |
38 Now we can define the lookup function for tries. It descends into the trie |
39 examining the letters of the search string one by one. As |
39 examining the letters of the search string one by one. As |
40 recursion on lists is simpler than on tries, let us express this as primitive |
40 recursion on lists is simpler than on tries, let us express this as primitive |
41 recursion on the search string argument: |
41 recursion on the search string argument: |
42 *}; |
42 *}; |
43 |
43 |
44 consts lookup :: "('a,'v)trie \<Rightarrow> 'a list \<Rightarrow> 'v option"; |
44 primrec lookup :: "('a,'v)trie \<Rightarrow> 'a list \<Rightarrow> 'v option" where |
45 primrec "lookup t [] = value t" |
45 "lookup t [] = value t" | |
46 "lookup t (a#as) = (case assoc (alist t) a of |
46 "lookup t (a#as) = (case assoc (alist t) a of |
47 None \<Rightarrow> None |
47 None \<Rightarrow> None |
48 | Some at \<Rightarrow> lookup at as)"; |
48 | Some at \<Rightarrow> lookup at as)" |
49 |
49 |
50 text{* |
50 text{* |
51 As a first simple property we prove that looking up a string in the empty |
51 As a first simple property we prove that looking up a string in the empty |
52 trie @{term"Trie None []"} always returns @{const None}. The proof merely |
52 trie @{term"Trie None []"} always returns @{const None}. The proof merely |
53 distinguishes the two cases whether the search string is empty or not: |
53 distinguishes the two cases whether the search string is empty or not: |
61 Things begin to get interesting with the definition of an update function |
61 Things begin to get interesting with the definition of an update function |
62 that adds a new (string, value) pair to a trie, overwriting the old value |
62 that adds a new (string, value) pair to a trie, overwriting the old value |
63 associated with that string: |
63 associated with that string: |
64 *}; |
64 *}; |
65 |
65 |
66 consts update :: "('a,'v)trie \<Rightarrow> 'a list \<Rightarrow> 'v \<Rightarrow> ('a,'v)trie"; |
66 primrec update:: "('a,'v)trie \<Rightarrow> 'a list \<Rightarrow> 'v \<Rightarrow> ('a,'v)trie" where |
67 primrec |
67 "update t [] v = Trie (Some v) (alist t)" | |
68 "update t [] v = Trie (Some v) (alist t)" |
68 "update t (a#as) v = |
69 "update t (a#as) v = |
69 (let tt = (case assoc (alist t) a of |
70 (let tt = (case assoc (alist t) a of |
70 None \<Rightarrow> Trie None [] | Some at \<Rightarrow> at) |
71 None \<Rightarrow> Trie None [] | Some at \<Rightarrow> at) |
71 in Trie (value t) ((a,update tt as v) # alist t))" |
72 in Trie (value t) ((a,update tt as v) # alist t))"; |
|
73 |
72 |
74 text{*\noindent |
73 text{*\noindent |
75 The base case is obvious. In the recursive case the subtrie |
74 The base case is obvious. In the recursive case the subtrie |
76 @{term tt} associated with the first letter @{term a} is extracted, |
75 @{term tt} associated with the first letter @{term a} is extracted, |
77 recursively updated, and then placed in front of the association list. |
76 recursively updated, and then placed in front of the association list. |
163 |
162 |
164 (*<*) |
163 (*<*) |
165 |
164 |
166 (* Exercise 1. Solution by Getrud Bauer *) |
165 (* Exercise 1. Solution by Getrud Bauer *) |
167 |
166 |
168 consts update1 :: "('a, 'v) trie \<Rightarrow> 'a list \<Rightarrow> 'v option \<Rightarrow> ('a, 'v) trie" |
167 primrec update1 :: "('a, 'v) trie \<Rightarrow> 'a list \<Rightarrow> 'v option \<Rightarrow> ('a, 'v) trie" |
169 primrec |
168 where |
170 "update1 t [] vo = Trie vo (alist t)" |
169 "update1 t [] vo = Trie vo (alist t)" | |
171 "update1 t (a#as) vo = |
170 "update1 t (a#as) vo = |
172 (let tt = (case assoc (alist t) a of |
171 (let tt = (case assoc (alist t) a of |
173 None \<Rightarrow> Trie None [] |
172 None \<Rightarrow> Trie None [] |
174 | Some at \<Rightarrow> at) |
173 | Some at \<Rightarrow> at) |
175 in Trie (value t) ((a, update1 tt as vo) # alist t))" |
174 in Trie (value t) ((a, update1 tt as vo) # alist t))" |
181 done |
180 done |
182 |
181 |
183 |
182 |
184 (* Exercise 2. Solution by Getrud Bauer *) |
183 (* Exercise 2. Solution by Getrud Bauer *) |
185 |
184 |
186 consts overwrite :: "'a \<Rightarrow> 'b \<Rightarrow> ('a * 'b) list \<Rightarrow> ('a * 'b) list" |
185 primrec overwrite :: "'a \<Rightarrow> 'b \<Rightarrow> ('a * 'b) list \<Rightarrow> ('a * 'b) list" where |
187 primrec |
186 "overwrite a v [] = [(a,v)]" | |
188 "overwrite a v [] = [(a,v)]" |
187 "overwrite a v (p#ps) = (if a = fst p then (a,v)#ps else p # overwrite a v ps)" |
189 "overwrite a v (p#ps) = (if a = fst p then (a,v)#ps else p # overwrite a v ps)" |
|
190 |
188 |
191 lemma [simp]: "\<forall> a v b. assoc (overwrite a v ps) b = assoc ((a,v)#ps) b" |
189 lemma [simp]: "\<forall> a v b. assoc (overwrite a v ps) b = assoc ((a,v)#ps) b" |
192 apply (induct_tac ps, auto) |
190 apply (induct_tac ps, auto) |
193 apply (case_tac[!] a) |
191 apply (case_tac[!] a) |
194 done |
192 done |
195 |
193 |
196 consts update2 :: "('a, 'v) trie \<Rightarrow> 'a list \<Rightarrow> 'v option \<Rightarrow> ('a, 'v) trie"; |
194 primrec update2 :: "('a, 'v) trie \<Rightarrow> 'a list \<Rightarrow> 'v option \<Rightarrow> ('a, 'v) trie" |
197 primrec |
195 where |
198 "update2 t [] vo = Trie vo (alist t)" |
196 "update2 t [] vo = Trie vo (alist t)" | |
199 "update2 t (a#as) vo = |
197 "update2 t (a#as) vo = |
200 (let tt = (case assoc (alist t) a of |
198 (let tt = (case assoc (alist t) a of |
201 None \<Rightarrow> Trie None [] |
199 None \<Rightarrow> Trie None [] |
202 | Some at \<Rightarrow> at) |
200 | Some at \<Rightarrow> at) |
203 in Trie (value t) (overwrite a (update2 tt as vo) (alist t)))"; |
201 in Trie (value t) (overwrite a (update2 tt as vo) (alist t)))"; |
210 |
208 |
211 |
209 |
212 (* Exercise 3. Solution by Getrud Bauer *) |
210 (* Exercise 3. Solution by Getrud Bauer *) |
213 datatype ('a,'v) triem = Triem "'v option" "'a \<Rightarrow> ('a,'v) triem option"; |
211 datatype ('a,'v) triem = Triem "'v option" "'a \<Rightarrow> ('a,'v) triem option"; |
214 |
212 |
215 consts valuem :: "('a, 'v) triem \<Rightarrow> 'v option" |
213 primrec valuem :: "('a, 'v) triem \<Rightarrow> 'v option" where |
216 primrec "valuem (Triem ov m) = ov"; |
214 "valuem (Triem ov m) = ov" |
217 |
215 |
218 consts mapping :: "('a,'v) triem \<Rightarrow> 'a \<Rightarrow> ('a, 'v) triem option"; |
216 primrec mapping :: "('a,'v) triem \<Rightarrow> 'a \<Rightarrow> ('a, 'v) triem option" where |
219 primrec "mapping (Triem ov m) = m"; |
217 "mapping (Triem ov m) = m" |
220 |
218 |
221 consts lookupm :: "('a,'v) triem \<Rightarrow> 'a list \<Rightarrow> 'v option" |
219 primrec lookupm :: "('a,'v) triem \<Rightarrow> 'a list \<Rightarrow> 'v option" where |
222 primrec |
220 "lookupm t [] = valuem t" | |
223 "lookupm t [] = valuem t" |
|
224 "lookupm t (a#as) = (case mapping t a of |
221 "lookupm t (a#as) = (case mapping t a of |
225 None \<Rightarrow> None |
222 None \<Rightarrow> None |
226 | Some at \<Rightarrow> lookupm at as)"; |
223 | Some at \<Rightarrow> lookupm at as)"; |
227 |
224 |
228 lemma [simp]: "lookupm (Triem None (\<lambda>c. None)) as = None"; |
225 lemma [simp]: "lookupm (Triem None (\<lambda>c. None)) as = None"; |
229 apply (case_tac as, simp_all); |
226 apply (case_tac as, simp_all); |
230 done |
227 done |
231 |
228 |
232 consts updatem :: "('a,'v)triem \<Rightarrow> 'a list \<Rightarrow> 'v \<Rightarrow> ('a,'v)triem" |
229 primrec updatem :: "('a,'v)triem \<Rightarrow> 'a list \<Rightarrow> 'v \<Rightarrow> ('a,'v)triem" where |
233 primrec |
230 "updatem t [] v = Triem (Some v) (mapping t)" | |
234 "updatem t [] v = Triem (Some v) (mapping t)" |
|
235 "updatem t (a#as) v = |
231 "updatem t (a#as) v = |
236 (let tt = (case mapping t a of |
232 (let tt = (case mapping t a of |
237 None \<Rightarrow> Triem None (\<lambda>c. None) |
233 None \<Rightarrow> Triem None (\<lambda>c. None) |
238 | Some at \<Rightarrow> at) |
234 | Some at \<Rightarrow> at) |
239 in Triem (valuem t) |
235 in Triem (valuem t) |