38405
|
1 |
theory Refinement
|
|
2 |
imports Setup
|
|
3 |
begin
|
|
4 |
|
|
5 |
section {* Program and datatype refinement \label{sec:refinement} *}
|
|
6 |
|
38437
|
7 |
subsection {* Datatypes \label{sec:datatypes} *}
|
|
8 |
|
|
9 |
text {*
|
|
10 |
Conceptually, any datatype is spanned by a set of
|
|
11 |
\emph{constructors} of type @{text "\<tau> = \<dots> \<Rightarrow> \<kappa> \<alpha>\<^isub>1 \<dots> \<alpha>\<^isub>n"} where @{text
|
|
12 |
"{\<alpha>\<^isub>1, \<dots>, \<alpha>\<^isub>n}"} is exactly the set of \emph{all} type variables in
|
|
13 |
@{text "\<tau>"}. The HOL datatype package by default registers any new
|
|
14 |
datatype in the table of datatypes, which may be inspected using the
|
|
15 |
@{command print_codesetup} command.
|
|
16 |
|
|
17 |
In some cases, it is appropriate to alter or extend this table. As
|
|
18 |
an example, we will develop an alternative representation of the
|
|
19 |
queue example given in \secref{sec:queue_example}. The amortised
|
|
20 |
representation is convenient for generating code but exposes its
|
|
21 |
\qt{implementation} details, which may be cumbersome when proving
|
|
22 |
theorems about it. Therefore, here is a simple, straightforward
|
|
23 |
representation of queues:
|
|
24 |
*}
|
|
25 |
|
|
26 |
datatype %quote 'a queue = Queue "'a list"
|
|
27 |
|
|
28 |
definition %quote empty :: "'a queue" where
|
|
29 |
"empty = Queue []"
|
|
30 |
|
|
31 |
primrec %quote enqueue :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue" where
|
|
32 |
"enqueue x (Queue xs) = Queue (xs @ [x])"
|
|
33 |
|
|
34 |
fun %quote dequeue :: "'a queue \<Rightarrow> 'a option \<times> 'a queue" where
|
|
35 |
"dequeue (Queue []) = (None, Queue [])"
|
|
36 |
| "dequeue (Queue (x # xs)) = (Some x, Queue xs)"
|
|
37 |
|
|
38 |
text {*
|
|
39 |
\noindent This we can use directly for proving; for executing,
|
|
40 |
we provide an alternative characterisation:
|
|
41 |
*}
|
|
42 |
|
|
43 |
definition %quote AQueue :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a queue" where
|
|
44 |
"AQueue xs ys = Queue (ys @ rev xs)"
|
|
45 |
|
|
46 |
code_datatype %quote AQueue
|
|
47 |
|
|
48 |
text {*
|
|
49 |
\noindent Here we define a \qt{constructor} @{const "AQueue"} which
|
|
50 |
is defined in terms of @{text "Queue"} and interprets its arguments
|
|
51 |
according to what the \emph{content} of an amortised queue is supposed
|
|
52 |
to be. Equipped with this, we are able to prove the following equations
|
|
53 |
for our primitive queue operations which \qt{implement} the simple
|
|
54 |
queues in an amortised fashion:
|
|
55 |
*}
|
|
56 |
|
|
57 |
lemma %quote empty_AQueue [code]:
|
|
58 |
"empty = AQueue [] []"
|
|
59 |
unfolding AQueue_def empty_def by simp
|
|
60 |
|
|
61 |
lemma %quote enqueue_AQueue [code]:
|
|
62 |
"enqueue x (AQueue xs ys) = AQueue (x # xs) ys"
|
|
63 |
unfolding AQueue_def by simp
|
|
64 |
|
|
65 |
lemma %quote dequeue_AQueue [code]:
|
|
66 |
"dequeue (AQueue xs []) =
|
|
67 |
(if xs = [] then (None, AQueue [] [])
|
|
68 |
else dequeue (AQueue [] (rev xs)))"
|
|
69 |
"dequeue (AQueue xs (y # ys)) = (Some y, AQueue xs ys)"
|
|
70 |
unfolding AQueue_def by simp_all
|
|
71 |
|
|
72 |
text {*
|
|
73 |
\noindent For completeness, we provide a substitute for the
|
|
74 |
@{text case} combinator on queues:
|
|
75 |
*}
|
|
76 |
|
|
77 |
lemma %quote queue_case_AQueue [code]:
|
|
78 |
"queue_case f (AQueue xs ys) = f (ys @ rev xs)"
|
|
79 |
unfolding AQueue_def by simp
|
|
80 |
|
|
81 |
text {*
|
|
82 |
\noindent The resulting code looks as expected:
|
|
83 |
*}
|
|
84 |
|
|
85 |
text %quote {*@{code_stmts empty enqueue dequeue (SML)}*}
|
|
86 |
|
|
87 |
text {*
|
|
88 |
\noindent From this example, it can be glimpsed that using own
|
|
89 |
constructor sets is a little delicate since it changes the set of
|
|
90 |
valid patterns for values of that type. Without going into much
|
|
91 |
detail, here some practical hints:
|
|
92 |
|
|
93 |
\begin{itemize}
|
|
94 |
|
|
95 |
\item When changing the constructor set for datatypes, take care
|
|
96 |
to provide alternative equations for the @{text case} combinator.
|
|
97 |
|
|
98 |
\item Values in the target language need not to be normalised --
|
|
99 |
different values in the target language may represent the same
|
|
100 |
value in the logic.
|
|
101 |
|
|
102 |
\item Usually, a good methodology to deal with the subtleties of
|
|
103 |
pattern matching is to see the type as an abstract type: provide
|
|
104 |
a set of operations which operate on the concrete representation
|
|
105 |
of the type, and derive further operations by combinations of
|
|
106 |
these primitive ones, without relying on a particular
|
|
107 |
representation.
|
|
108 |
|
|
109 |
\end{itemize}
|
|
110 |
*}
|
|
111 |
|
38405
|
112 |
end
|