|
1 (* Title: HOL/Library/Nested_Environment.thy |
|
2 ID: $Id$ |
|
3 Author: Markus Wenzel, TU Muenchen |
|
4 License: GPL (GNU GENERAL PUBLIC LICENSE) |
|
5 *) |
|
6 |
|
7 header {* |
|
8 \title{Nested environments} |
|
9 \author{Markus Wenzel} |
|
10 *} |
|
11 |
|
12 theory Nested_Environment = Main: |
|
13 |
|
14 text {* |
|
15 Consider a partial function @{term [source] "e :: 'a => 'b option"}; |
|
16 this may be understood as an \emph{environment} mapping indexes |
|
17 @{typ 'a} to optional entry values @{typ 'b} (cf.\ the basic theory |
|
18 @{text |
|
19 Map}\footnote{\url{http://isabelle.in.tum.de/library/HOL/Map.html}} |
|
20 of Isabelle/HOL). This basic idea is easily generalized to that of |
|
21 a \emph{nested environment}, where entries may be either basic |
|
22 values or again proper environments. Then each entry is accessed by |
|
23 a \emph{path}, i.e.\ a list of indexes leading to its position |
|
24 within the structure. |
|
25 *} |
|
26 |
|
27 datatype ('a, 'b, 'c) env = |
|
28 Val 'a |
|
29 | Env 'b "'c => ('a, 'b, 'c) env option" |
|
30 |
|
31 text {* |
|
32 \medskip In the type @{typ "('a, 'b, 'c) env"} the parameter @{typ |
|
33 'a} refers to basic values (occurring in terminal positions), type |
|
34 @{typ 'b} to values associated with proper (inner) environments, and |
|
35 type @{typ 'c} with the index type for branching. Note that there |
|
36 is no restriction on any of these types. In particular, arbitrary |
|
37 branching may yield rather large (transfinite) tree structures. |
|
38 *} |
|
39 |
|
40 |
|
41 subsection {* The lookup operation *} |
|
42 |
|
43 text {* |
|
44 Lookup in nested environments works by following a given path of |
|
45 index elements, leading to an optional result (a terminal value or |
|
46 nested environment). A \emph{defined position} within a nested |
|
47 environment is one where @{term lookup} at its path does not yield |
|
48 @{term None}. |
|
49 *} |
|
50 |
|
51 consts |
|
52 lookup :: "('a, 'b, 'c) env => 'c list => ('a, 'b, 'c) env option" |
|
53 lookup_option :: "('a, 'b, 'c) env option => 'c list => ('a, 'b, 'c) env option" |
|
54 |
|
55 primrec (lookup) |
|
56 "lookup (Val a) xs = (if xs = [] then Some (Val a) else None)" |
|
57 "lookup (Env b es) xs = |
|
58 (case xs of |
|
59 [] => Some (Env b es) |
|
60 | y # ys => lookup_option (es y) ys)" |
|
61 "lookup_option None xs = None" |
|
62 "lookup_option (Some e) xs = lookup e xs" |
|
63 |
|
64 hide const lookup_option |
|
65 |
|
66 text {* |
|
67 \medskip The characteristic cases of @{term lookup} are expressed by |
|
68 the following equalities. |
|
69 *} |
|
70 |
|
71 theorem lookup_nil: "lookup e [] = Some e" |
|
72 by (cases e) simp_all |
|
73 |
|
74 theorem lookup_val_cons: "lookup (Val a) (x # xs) = None" |
|
75 by simp |
|
76 |
|
77 theorem lookup_env_cons: |
|
78 "lookup (Env b es) (x # xs) = |
|
79 (case es x of |
|
80 None => None |
|
81 | Some e => lookup e xs)" |
|
82 by (cases "es x") simp_all |
|
83 |
|
84 lemmas lookup.simps [simp del] |
|
85 and lookup_simps [simp] = lookup_nil lookup_val_cons lookup_env_cons |
|
86 |
|
87 theorem lookup_eq: |
|
88 "lookup env xs = |
|
89 (case xs of |
|
90 [] => Some env |
|
91 | x # xs => |
|
92 (case env of |
|
93 Val a => None |
|
94 | Env b es => |
|
95 (case es x of |
|
96 None => None |
|
97 | Some e => lookup e xs)))" |
|
98 by (simp split: list.split env.split) |
|
99 |
|
100 text {* |
|
101 \medskip Displaced @{term lookup} operations, relative to a certain |
|
102 base path prefix, may be reduced as follows. There are two cases, |
|
103 depending whether the environment actually extends far enough to |
|
104 follow the base path. |
|
105 *} |
|
106 |
|
107 theorem lookup_append_none: |
|
108 "!!env. lookup env xs = None ==> lookup env (xs @ ys) = None" |
|
109 (is "PROP ?P xs") |
|
110 proof (induct xs) |
|
111 fix env :: "('a, 'b, 'c) env" |
|
112 { |
|
113 assume "lookup env [] = None" |
|
114 hence False by simp |
|
115 thus "lookup env ([] @ ys) = None" .. |
|
116 next |
|
117 fix x xs |
|
118 assume hyp: "PROP ?P xs" |
|
119 assume asm: "lookup env (x # xs) = None" |
|
120 show "lookup env ((x # xs) @ ys) = None" |
|
121 proof (cases env) |
|
122 case Val |
|
123 thus ?thesis by simp |
|
124 next |
|
125 fix b es assume env: "env = Env b es" |
|
126 show ?thesis |
|
127 proof (cases "es x") |
|
128 assume "es x = None" |
|
129 with env show ?thesis by simp |
|
130 next |
|
131 fix e assume es: "es x = Some e" |
|
132 show ?thesis |
|
133 proof (cases "lookup e xs") |
|
134 case None |
|
135 hence "lookup e (xs @ ys) = None" by (rule hyp) |
|
136 with env es show ?thesis by simp |
|
137 next |
|
138 case Some |
|
139 with asm env es have False by simp |
|
140 thus ?thesis .. |
|
141 qed |
|
142 qed |
|
143 qed |
|
144 } |
|
145 qed |
|
146 |
|
147 theorem lookup_append_some: |
|
148 "!!env e. lookup env xs = Some e ==> lookup env (xs @ ys) = lookup e ys" |
|
149 (is "PROP ?P xs") |
|
150 proof (induct xs) |
|
151 fix env e :: "('a, 'b, 'c) env" |
|
152 { |
|
153 assume "lookup env [] = Some e" |
|
154 hence "env = e" by simp |
|
155 thus "lookup env ([] @ ys) = lookup e ys" by simp |
|
156 next |
|
157 fix x xs |
|
158 assume hyp: "PROP ?P xs" |
|
159 assume asm: "lookup env (x # xs) = Some e" |
|
160 show "lookup env ((x # xs) @ ys) = lookup e ys" |
|
161 proof (cases env) |
|
162 fix a assume "env = Val a" |
|
163 with asm have False by simp |
|
164 thus ?thesis .. |
|
165 next |
|
166 fix b es assume env: "env = Env b es" |
|
167 show ?thesis |
|
168 proof (cases "es x") |
|
169 assume "es x = None" |
|
170 with asm env have False by simp |
|
171 thus ?thesis .. |
|
172 next |
|
173 fix e' assume es: "es x = Some e'" |
|
174 show ?thesis |
|
175 proof (cases "lookup e' xs") |
|
176 case None |
|
177 with asm env es have False by simp |
|
178 thus ?thesis .. |
|
179 next |
|
180 case Some |
|
181 with asm env es have "lookup e' xs = Some e" |
|
182 by simp |
|
183 hence "lookup e' (xs @ ys) = lookup e ys" by (rule hyp) |
|
184 with env es show ?thesis by simp |
|
185 qed |
|
186 qed |
|
187 qed |
|
188 } |
|
189 qed |
|
190 |
|
191 text {* |
|
192 \medskip Successful @{term lookup} deeper down an environment |
|
193 structure means we are able to peek further up as well. Note that |
|
194 this is basically just the contrapositive statement of @{thm |
|
195 [source] lookup_append_none} above. |
|
196 *} |
|
197 |
|
198 theorem lookup_some_append: |
|
199 "lookup env (xs @ ys) = Some e ==> \<exists>e. lookup env xs = Some e" |
|
200 proof - |
|
201 assume "lookup env (xs @ ys) = Some e" |
|
202 hence "lookup env (xs @ ys) \<noteq> None" by simp |
|
203 hence "lookup env xs \<noteq> None" |
|
204 by (rule contrapos_nn) (simp only: lookup_append_none) |
|
205 thus ?thesis by simp |
|
206 qed |
|
207 |
|
208 text {* |
|
209 The subsequent statement describes in more detail how a successful |
|
210 @{term lookup} with a non-empty path results in a certain situation |
|
211 at any upper position. |
|
212 *} |
|
213 |
|
214 theorem lookup_some_upper: "!!env e. |
|
215 lookup env (xs @ y # ys) = Some e ==> |
|
216 \<exists>b' es' env'. |
|
217 lookup env xs = Some (Env b' es') \<and> |
|
218 es' y = Some env' \<and> |
|
219 lookup env' ys = Some e" |
|
220 (is "PROP ?P xs" is "!!env e. ?A env e xs ==> ?C env e xs") |
|
221 proof (induct ?P xs) |
|
222 fix env e |
|
223 let ?A = "?A env e" and ?C = "?C env e" |
|
224 { |
|
225 assume "?A []" |
|
226 hence "lookup env (y # ys) = Some e" by simp |
|
227 then obtain b' es' env' where |
|
228 env: "env = Env b' es'" |
|
229 and es': "es' y = Some env'" |
|
230 and look': "lookup env' ys = Some e" |
|
231 by (auto simp add: lookup_eq split: option.splits env.splits) |
|
232 from env have "lookup env [] = Some (Env b' es')" by simp |
|
233 with es' look' show "?C []" by blast |
|
234 next |
|
235 fix x xs |
|
236 assume hyp: "PROP ?P xs" |
|
237 assume "?A (x # xs)" |
|
238 then obtain b' es' env' where |
|
239 env: "env = Env b' es'" |
|
240 and es': "es' x = Some env'" |
|
241 and look': "lookup env' (xs @ y # ys) = Some e" |
|
242 by (auto simp add: lookup_eq split: option.splits env.splits) |
|
243 from hyp [OF look'] obtain b'' es'' env'' where |
|
244 upper': "lookup env' xs = Some (Env b'' es'')" |
|
245 and es'': "es'' y = Some env''" |
|
246 and look'': "lookup env'' ys = Some e" |
|
247 by blast |
|
248 from env es' upper' have "lookup env (x # xs) = Some (Env b'' es'')" |
|
249 by simp |
|
250 with es'' look'' show "?C (x # xs)" by blast |
|
251 } |
|
252 qed |
|
253 |
|
254 |
|
255 subsection {* The update operation *} |
|
256 |
|
257 text {* |
|
258 Update at a certain position in a nested environment may either |
|
259 delete an existing entry, or overwrite an existing one. Note that |
|
260 update at undefined positions is simple absorbed, i.e.\ the |
|
261 environment is left unchanged. |
|
262 *} |
|
263 |
|
264 consts |
|
265 update :: "'c list => ('a, 'b, 'c) env option |
|
266 => ('a, 'b, 'c) env => ('a, 'b, 'c) env" |
|
267 update_option :: "'c list => ('a, 'b, 'c) env option |
|
268 => ('a, 'b, 'c) env option => ('a, 'b, 'c) env option" |
|
269 |
|
270 primrec (update) |
|
271 "update xs opt (Val a) = |
|
272 (if xs = [] then (case opt of None => Val a | Some e => e) |
|
273 else Val a)" |
|
274 "update xs opt (Env b es) = |
|
275 (case xs of |
|
276 [] => (case opt of None => Env b es | Some e => e) |
|
277 | y # ys => Env b (es (y := update_option ys opt (es y))))" |
|
278 "update_option xs opt None = |
|
279 (if xs = [] then opt else None)" |
|
280 "update_option xs opt (Some e) = |
|
281 (if xs = [] then opt else Some (update xs opt e))" |
|
282 |
|
283 hide const update_option |
|
284 |
|
285 text {* |
|
286 \medskip The characteristic cases of @{term update} are expressed by |
|
287 the following equalities. |
|
288 *} |
|
289 |
|
290 theorem update_nil_none: "update [] None env = env" |
|
291 by (cases env) simp_all |
|
292 |
|
293 theorem update_nil_some: "update [] (Some e) env = e" |
|
294 by (cases env) simp_all |
|
295 |
|
296 theorem update_cons_val: "update (x # xs) opt (Val a) = Val a" |
|
297 by simp |
|
298 |
|
299 theorem update_cons_nil_env: |
|
300 "update [x] opt (Env b es) = Env b (es (x := opt))" |
|
301 by (cases "es x") simp_all |
|
302 |
|
303 theorem update_cons_cons_env: |
|
304 "update (x # y # ys) opt (Env b es) = |
|
305 Env b (es (x := |
|
306 (case es x of |
|
307 None => None |
|
308 | Some e => Some (update (y # ys) opt e))))" |
|
309 by (cases "es x") simp_all |
|
310 |
|
311 lemmas update.simps [simp del] |
|
312 and update_simps [simp] = update_nil_none update_nil_some |
|
313 update_cons_val update_cons_nil_env update_cons_cons_env |
|
314 |
|
315 lemma update_eq: |
|
316 "update xs opt env = |
|
317 (case xs of |
|
318 [] => |
|
319 (case opt of |
|
320 None => env |
|
321 | Some e => e) |
|
322 | x # xs => |
|
323 (case env of |
|
324 Val a => Val a |
|
325 | Env b es => |
|
326 (case xs of |
|
327 [] => Env b (es (x := opt)) |
|
328 | y # ys => |
|
329 Env b (es (x := |
|
330 (case es x of |
|
331 None => None |
|
332 | Some e => Some (update (y # ys) opt e)))))))" |
|
333 by (simp split: list.split env.split option.split) |
|
334 |
|
335 text {* |
|
336 \medskip The most basic correspondence of @{term lookup} and @{term |
|
337 update} states that after @{term update} at a defined position, |
|
338 subsequent @{term lookup} operations would yield the new value. |
|
339 *} |
|
340 |
|
341 theorem lookup_update_some: |
|
342 "!!env e. lookup env xs = Some e ==> |
|
343 lookup (update xs (Some env') env) xs = Some env'" |
|
344 (is "PROP ?P xs") |
|
345 proof (induct xs) |
|
346 fix env e :: "('a, 'b, 'c) env" |
|
347 { |
|
348 assume "lookup env [] = Some e" |
|
349 hence "env = e" by simp |
|
350 thus "lookup (update [] (Some env') env) [] = Some env'" |
|
351 by simp |
|
352 next |
|
353 fix x xs |
|
354 assume hyp: "PROP ?P xs" |
|
355 assume asm: "lookup env (x # xs) = Some e" |
|
356 show "lookup (update (x # xs) (Some env') env) (x # xs) = Some env'" |
|
357 proof (cases env) |
|
358 fix a assume "env = Val a" |
|
359 with asm have False by simp |
|
360 thus ?thesis .. |
|
361 next |
|
362 fix b es assume env: "env = Env b es" |
|
363 show ?thesis |
|
364 proof (cases "es x") |
|
365 assume "es x = None" |
|
366 with asm env have False by simp |
|
367 thus ?thesis .. |
|
368 next |
|
369 fix e' assume es: "es x = Some e'" |
|
370 show ?thesis |
|
371 proof (cases xs) |
|
372 assume "xs = []" |
|
373 with env show ?thesis by simp |
|
374 next |
|
375 fix x' xs' assume xs: "xs = x' # xs'" |
|
376 from asm env es have "lookup e' xs = Some e" by simp |
|
377 hence "lookup (update xs (Some env') e') xs = Some env'" by (rule hyp) |
|
378 with env es xs show ?thesis by simp |
|
379 qed |
|
380 qed |
|
381 qed |
|
382 } |
|
383 qed |
|
384 |
|
385 text {* |
|
386 \medskip The properties of displaced @{term update} operations are |
|
387 analogous to those of @{term lookup} above. There are two cases: |
|
388 below an undefined position @{term update} is absorbed altogether, |
|
389 and below a defined positions @{term update} affects subsequent |
|
390 @{term lookup} operations in the obvious way. |
|
391 *} |
|
392 |
|
393 theorem update_append_none: |
|
394 "!!env. lookup env xs = None ==> update (xs @ y # ys) opt env = env" |
|
395 (is "PROP ?P xs") |
|
396 proof (induct xs) |
|
397 fix env :: "('a, 'b, 'c) env" |
|
398 { |
|
399 assume "lookup env [] = None" |
|
400 hence False by simp |
|
401 thus "update ([] @ y # ys) opt env = env" .. |
|
402 next |
|
403 fix x xs |
|
404 assume hyp: "PROP ?P xs" |
|
405 assume asm: "lookup env (x # xs) = None" |
|
406 show "update ((x # xs) @ y # ys) opt env = env" |
|
407 proof (cases env) |
|
408 fix a assume "env = Val a" |
|
409 thus ?thesis by simp |
|
410 next |
|
411 fix b es assume env: "env = Env b es" |
|
412 show ?thesis |
|
413 proof (cases "es x") |
|
414 assume es: "es x = None" |
|
415 show ?thesis |
|
416 by (cases xs) (simp_all add: es env fun_upd_idem_iff) |
|
417 next |
|
418 fix e assume es: "es x = Some e" |
|
419 show ?thesis |
|
420 proof (cases xs) |
|
421 assume "xs = []" |
|
422 with asm env es have False by simp |
|
423 thus ?thesis .. |
|
424 next |
|
425 fix x' xs' assume xs: "xs = x' # xs'" |
|
426 from asm env es have "lookup e xs = None" by simp |
|
427 hence "update (xs @ y # ys) opt e = e" by (rule hyp) |
|
428 with env es xs show "update ((x # xs) @ y # ys) opt env = env" |
|
429 by (simp add: fun_upd_idem_iff) |
|
430 qed |
|
431 qed |
|
432 qed |
|
433 } |
|
434 qed |
|
435 |
|
436 theorem update_append_some: |
|
437 "!!env e. lookup env xs = Some e ==> |
|
438 lookup (update (xs @ y # ys) opt env) xs = Some (update (y # ys) opt e)" |
|
439 (is "PROP ?P xs") |
|
440 proof (induct xs) |
|
441 fix env e :: "('a, 'b, 'c) env" |
|
442 { |
|
443 assume "lookup env [] = Some e" |
|
444 hence "env = e" by simp |
|
445 thus "lookup (update ([] @ y # ys) opt env) [] = Some (update (y # ys) opt e)" |
|
446 by simp |
|
447 next |
|
448 fix x xs |
|
449 assume hyp: "PROP ?P xs" |
|
450 assume asm: "lookup env (x # xs) = Some e" |
|
451 show "lookup (update ((x # xs) @ y # ys) opt env) (x # xs) |
|
452 = Some (update (y # ys) opt e)" |
|
453 proof (cases env) |
|
454 fix a assume "env = Val a" |
|
455 with asm have False by simp |
|
456 thus ?thesis .. |
|
457 next |
|
458 fix b es assume env: "env = Env b es" |
|
459 show ?thesis |
|
460 proof (cases "es x") |
|
461 assume "es x = None" |
|
462 with asm env have False by simp |
|
463 thus ?thesis .. |
|
464 next |
|
465 fix e' assume es: "es x = Some e'" |
|
466 show ?thesis |
|
467 proof (cases xs) |
|
468 assume xs: "xs = []" |
|
469 from asm env es xs have "e = e'" by simp |
|
470 with env es xs show ?thesis by simp |
|
471 next |
|
472 fix x' xs' assume xs: "xs = x' # xs'" |
|
473 from asm env es have "lookup e' xs = Some e" by simp |
|
474 hence "lookup (update (xs @ y # ys) opt e') xs = |
|
475 Some (update (y # ys) opt e)" by (rule hyp) |
|
476 with env es xs show ?thesis by simp |
|
477 qed |
|
478 qed |
|
479 qed |
|
480 } |
|
481 qed |
|
482 |
|
483 text {* |
|
484 \medskip Apparently, @{term update} does not affect the result of |
|
485 subsequent @{term lookup} operations at independent positions, i.e.\ |
|
486 in case that the paths for @{term update} and @{term lookup} fork at |
|
487 a certain point. |
|
488 *} |
|
489 |
|
490 theorem lookup_update_other: |
|
491 "!!env. y \<noteq> (z::'c) ==> lookup (update (xs @ z # zs) opt env) (xs @ y # ys) = |
|
492 lookup env (xs @ y # ys)" |
|
493 (is "PROP ?P xs") |
|
494 proof (induct xs) |
|
495 fix env :: "('a, 'b, 'c) env" |
|
496 assume neq: "y \<noteq> z" |
|
497 { |
|
498 show "lookup (update ([] @ z # zs) opt env) ([] @ y # ys) = |
|
499 lookup env ([] @ y # ys)" |
|
500 proof (cases env) |
|
501 case Val |
|
502 thus ?thesis by simp |
|
503 next |
|
504 case Env |
|
505 show ?thesis |
|
506 proof (cases zs) |
|
507 case Nil |
|
508 with neq Env show ?thesis by simp |
|
509 next |
|
510 case Cons |
|
511 with neq Env show ?thesis by simp |
|
512 qed |
|
513 qed |
|
514 next |
|
515 fix x xs |
|
516 assume hyp: "PROP ?P xs" |
|
517 show "lookup (update ((x # xs) @ z # zs) opt env) ((x # xs) @ y # ys) = |
|
518 lookup env ((x # xs) @ y # ys)" |
|
519 proof (cases env) |
|
520 case Val |
|
521 thus ?thesis by simp |
|
522 next |
|
523 fix y es assume env: "env = Env y es" |
|
524 show ?thesis |
|
525 proof (cases xs) |
|
526 assume xs: "xs = []" |
|
527 show ?thesis |
|
528 proof (cases "es x") |
|
529 case None |
|
530 with env xs show ?thesis by simp |
|
531 next |
|
532 case Some |
|
533 with hyp env xs and neq show ?thesis by simp |
|
534 qed |
|
535 next |
|
536 fix x' xs' assume xs: "xs = x' # xs'" |
|
537 show ?thesis |
|
538 proof (cases "es x") |
|
539 case None |
|
540 with env xs show ?thesis by simp |
|
541 next |
|
542 case Some |
|
543 with hyp env xs neq show ?thesis by simp |
|
544 qed |
|
545 qed |
|
546 qed |
|
547 } |
|
548 qed |
|
549 |
|
550 end |