doc-src/TutorialI/Trie/Trie.thy
changeset 27015 f8537d69f514
parent 17555 23c4a349feff
equal deleted inserted replaced
27014:a5f53d9d2b60 27015:f8537d69f514
    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)