24 could provide an alternative code equations for @{const dequeue} |
24 could provide an alternative code equations for @{const dequeue} |
25 explicitly: |
25 explicitly: |
26 *} |
26 *} |
27 |
27 |
28 lemma %quote [code]: |
28 lemma %quote [code]: |
29 "dequeue (Queue xs []) = |
29 "dequeue (AQueue xs []) = |
30 (if xs = [] then (None, Queue [] []) |
30 (if xs = [] then (None, AQueue [] []) |
31 else dequeue (Queue [] (rev xs)))" |
31 else dequeue (AQueue [] (rev xs)))" |
32 "dequeue (Queue xs (y # ys)) = |
32 "dequeue (AQueue xs (y # ys)) = |
33 (Some y, Queue xs ys)" |
33 (Some y, AQueue xs ys)" |
34 by (cases xs, simp_all) (cases "rev xs", simp_all) |
34 by (cases xs, simp_all) (cases "rev xs", simp_all) |
35 |
35 |
36 text {* |
36 text {* |
37 \noindent The annotation @{text "[code]"} is an @{text Isar} |
37 \noindent The annotation @{text "[code]"} is an @{text Isar} |
38 @{text attribute} which states that the given theorems should be |
38 @{text attribute} which states that the given theorems should be |
256 definition %quote AQueue :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a queue" where |
256 definition %quote AQueue :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a queue" where |
257 "AQueue xs ys = Queue (ys @ rev xs)" |
257 "AQueue xs ys = Queue (ys @ rev xs)" |
258 |
258 |
259 code_datatype %quote AQueue |
259 code_datatype %quote AQueue |
260 |
260 |
261 text {* *} |
261 text {* |
|
262 \noindent Here we define a \qt{constructor} @{const "AQueue"} which |
|
263 is defined in terms of @{text "Queue"} and interprets its arguments |
|
264 according to what the \emph{content} of an amortised queue is supposed |
|
265 to be. Equipped with this, we are able to prove the following equations |
|
266 for our primitive queue operations which \qt{implement} the simple |
|
267 queues in an amortised fashion: |
|
268 *} |
262 |
269 |
263 lemma %quote empty_AQueue [code]: |
270 lemma %quote empty_AQueue [code]: |
264 "empty = AQueue [] []" |
271 "empty = AQueue [] []" |
265 unfolding AQueue_def empty_def by simp |
272 unfolding AQueue_def empty_def by simp |
266 |
273 |
268 "enqueue x (AQueue xs ys) = AQueue (x # xs) ys" |
275 "enqueue x (AQueue xs ys) = AQueue (x # xs) ys" |
269 unfolding AQueue_def by simp |
276 unfolding AQueue_def by simp |
270 |
277 |
271 lemma %quote dequeue_AQueue [code]: |
278 lemma %quote dequeue_AQueue [code]: |
272 "dequeue (AQueue xs []) = |
279 "dequeue (AQueue xs []) = |
273 (if xs = [] then (None, AQueue [] []) else dequeue (AQueue [] (rev xs)))" |
280 (if xs = [] then (None, AQueue [] []) |
|
281 else dequeue (AQueue [] (rev xs)))" |
274 "dequeue (AQueue xs (y # ys)) = (Some y, AQueue xs ys)" |
282 "dequeue (AQueue xs (y # ys)) = (Some y, AQueue xs ys)" |
275 unfolding AQueue_def by simp_all |
283 unfolding AQueue_def by simp_all |
276 |
284 |
277 text {* *} |
285 text {* |
278 |
286 \noindent For completeness, we provide a substitute for the |
279 definition %quote aqueue_case [code inline]: |
287 @{text case} combinator on queues: |
280 "aqueue_case = queue_case" |
288 *} |
281 |
289 |
282 lemma %quote case_AQueue1 [code]: |
290 definition %quote |
283 "queue_case f (AQueue xs ys) = f (ys @ rev xs)" |
291 aqueue_case_def: "aqueue_case = queue_case" |
284 unfolding AQueue_def by simp |
292 |
285 |
293 lemma %quote aqueue_case [code, code inline]: |
286 lemma %quote case_AQueue2 [code]: |
294 "queue_case = aqueue_case" |
|
295 unfolding aqueue_case_def .. |
|
296 |
|
297 lemma %quote case_AQueue [code]: |
287 "aqueue_case f (AQueue xs ys) = f (ys @ rev xs)" |
298 "aqueue_case f (AQueue xs ys) = f (ys @ rev xs)" |
288 unfolding aqueue_case case_AQueue1 .. |
299 unfolding aqueue_case_def AQueue_def by simp |
289 |
300 |
290 text {* *} |
301 text {* |
|
302 \noindent The resulting code looks as expected: |
|
303 *} |
291 |
304 |
292 text %quote {*@{code_stmts empty enqueue dequeue (SML)}*} |
305 text %quote {*@{code_stmts empty enqueue dequeue (SML)}*} |
293 |
306 |
294 text {* |
307 text {* |
295 \noindent From this example, it can be glimpsed that using own |
308 \noindent From this example, it can be glimpsed that using own |
451 text {* |
464 text {* |
452 Partiality usually enters the game by partial patterns, as |
465 Partiality usually enters the game by partial patterns, as |
453 in the following example, again for amortised queues: |
466 in the following example, again for amortised queues: |
454 *} |
467 *} |
455 |
468 |
456 fun %quote strict_dequeue :: "'a Introduction.queue \<Rightarrow> 'a \<times> 'a Introduction.queue" where |
469 definition %quote strict_dequeue :: "'a queue \<Rightarrow> 'a \<times> 'a queue" where |
457 "strict_dequeue (Introduction.Queue xs (y # ys)) = (y, Introduction.Queue xs ys)" |
470 "strict_dequeue q = (case dequeue q |
458 | "strict_dequeue (Introduction.Queue xs []) = |
471 of (Some x, q') \<Rightarrow> (x, q'))" |
459 (case rev xs of y # ys \<Rightarrow> (y, Introduction.Queue [] ys))" |
472 |
|
473 lemma %quote strict_dequeue_AQueue [code]: |
|
474 "strict_dequeue (AQueue xs (y # ys)) = (y, AQueue xs ys)" |
|
475 "strict_dequeue (AQueue xs []) = |
|
476 (case rev xs of y # ys \<Rightarrow> (y, AQueue [] ys))" |
|
477 by (simp_all add: strict_dequeue_def dequeue_AQueue split: list.splits) |
460 |
478 |
461 text {* |
479 text {* |
462 \noindent In the corresponding code, there is no equation |
480 \noindent In the corresponding code, there is no equation |
463 for the pattern @{term "Introduction.Queue [] []"}: |
481 for the pattern @{term "AQueue [] []"}: |
464 *} |
482 *} |
465 |
483 |
466 text %quote {*@{code_stmts strict_dequeue (consts) strict_dequeue (Haskell)}*} |
484 text %quote {*@{code_stmts strict_dequeue (consts) strict_dequeue (Haskell)}*} |
467 |
485 |
468 text {* |
486 text {* |
470 pseudo-\qt{partiality} more explicitly, e.g.~as follows: |
488 pseudo-\qt{partiality} more explicitly, e.g.~as follows: |
471 *} |
489 *} |
472 |
490 |
473 axiomatization %quote empty_queue :: 'a |
491 axiomatization %quote empty_queue :: 'a |
474 |
492 |
475 function %quote strict_dequeue' :: "'a Introduction.queue \<Rightarrow> 'a \<times> 'a Introduction.queue" where |
493 definition %quote strict_dequeue' :: "'a queue \<Rightarrow> 'a \<times> 'a queue" where |
476 "strict_dequeue' (Introduction.Queue xs []) = (if xs = [] then empty_queue |
494 "strict_dequeue' q = (case dequeue q of (Some x, q') \<Rightarrow> (x, q') | _ \<Rightarrow> empty_queue)" |
477 else strict_dequeue' (Introduction.Queue [] (rev xs)))" |
495 |
478 | "strict_dequeue' (Introduction.Queue xs (y # ys)) = |
496 lemma %quote strict_dequeue'_AQueue [code]: |
479 (y, Introduction.Queue xs ys)" |
497 "strict_dequeue' (AQueue xs []) = (if xs = [] then empty_queue |
480 by pat_completeness auto |
498 else strict_dequeue' (AQueue [] (rev xs)))" |
481 |
499 "strict_dequeue' (AQueue xs (y # ys)) = |
482 termination %quote strict_dequeue' |
500 (y, AQueue xs ys)" |
483 by (relation "measure (\<lambda>q::'a Introduction.queue. case q of Introduction.Queue xs ys \<Rightarrow> length xs)") simp_all |
501 by (simp_all add: strict_dequeue'_def dequeue_AQueue split: list.splits) |
484 |
502 |
485 text {* |
503 text {* |
486 \noindent For technical reasons the definition of |
504 Observe that on the right hand side of the definition of @{const |
487 @{const strict_dequeue'} is more involved since it requires |
505 "strict_dequeue'"} the constant @{const empty_queue} occurs |
488 a manual termination proof. Apart from that observe that |
506 which is unspecified. |
489 on the right hand side of its first equation the constant |
507 |
490 @{const empty_queue} occurs which is unspecified. |
508 Normally, if constants without any code equations occur in a |
491 |
509 program, the code generator complains (since in most cases this is |
492 Normally, if constants without any code equations occur in |
510 not what the user expects). But such constants can also be thought |
493 a program, the code generator complains (since in most cases |
511 of as function definitions with no equations which always fail, |
494 this is not what the user expects). But such constants can also |
512 since there is never a successful pattern match on the left hand |
495 be thought of as function definitions with no equations which |
513 side. In order to categorise a constant into that category |
496 always fail, since there is never a successful pattern match |
514 explicitly, use @{command "code_abort"}: |
497 on the left hand side. In order to categorise a constant into |
|
498 that category explicitly, use @{command "code_abort"}: |
|
499 *} |
515 *} |
500 |
516 |
501 code_abort %quote empty_queue |
517 code_abort %quote empty_queue |
502 |
518 |
503 text {* |
519 text {* |