haftmann@28213
|
1 |
theory Further
|
haftmann@28213
|
2 |
imports Setup
|
haftmann@28213
|
3 |
begin
|
haftmann@28213
|
4 |
|
haftmann@28447
|
5 |
section {* Further issues \label{sec:further} *}
|
haftmann@28213
|
6 |
|
haftmann@28419
|
7 |
subsection {* Further reading *}
|
haftmann@28419
|
8 |
|
haftmann@28419
|
9 |
text {*
|
paulson@34155
|
10 |
To dive deeper into the issue of code generation, you should visit
|
paulson@34155
|
11 |
the Isabelle/Isar Reference Manual \cite{isabelle-isar-ref}, which
|
haftmann@28593
|
12 |
contains exhaustive syntax diagrams.
|
haftmann@28419
|
13 |
*}
|
haftmann@28419
|
14 |
|
haftmann@37401
|
15 |
subsection {* Locales and interpretation *}
|
haftmann@37401
|
16 |
|
haftmann@37401
|
17 |
lemma funpow_mult: -- FIXME
|
haftmann@37401
|
18 |
fixes f :: "'a \<Rightarrow> 'a"
|
haftmann@37401
|
19 |
shows "(f ^^ m) ^^ n = f ^^ (m * n)"
|
haftmann@37401
|
20 |
by (induct n) (simp_all add: funpow_add)
|
haftmann@37401
|
21 |
|
haftmann@37401
|
22 |
text {*
|
haftmann@37401
|
23 |
A technical issue comes to surface when generating code from
|
haftmann@37401
|
24 |
specifications stemming from locale interpretation.
|
haftmann@37401
|
25 |
|
haftmann@37401
|
26 |
Let us assume a locale specifying a power operation
|
haftmann@37401
|
27 |
on arbitrary types:
|
haftmann@37401
|
28 |
*}
|
haftmann@37401
|
29 |
|
haftmann@37401
|
30 |
locale %quote power =
|
haftmann@37401
|
31 |
fixes power :: "'a \<Rightarrow> 'b \<Rightarrow> 'b"
|
haftmann@37401
|
32 |
assumes power_commute: "power x \<circ> power y = power y \<circ> power x"
|
haftmann@37401
|
33 |
begin
|
haftmann@37401
|
34 |
|
haftmann@37401
|
35 |
text {*
|
haftmann@37401
|
36 |
\noindent Inside that locale we can lift @{text power} to exponent lists
|
haftmann@37401
|
37 |
by means of specification relative to that locale:
|
haftmann@37401
|
38 |
*}
|
haftmann@37401
|
39 |
|
haftmann@37401
|
40 |
primrec %quote powers :: "'a list \<Rightarrow> 'b \<Rightarrow> 'b" where
|
haftmann@37401
|
41 |
"powers [] = id"
|
haftmann@37401
|
42 |
| "powers (x # xs) = power x \<circ> powers xs"
|
haftmann@37401
|
43 |
|
haftmann@37401
|
44 |
lemma %quote powers_append:
|
haftmann@37401
|
45 |
"powers (xs @ ys) = powers xs \<circ> powers ys"
|
haftmann@37401
|
46 |
by (induct xs) simp_all
|
haftmann@37401
|
47 |
|
haftmann@37401
|
48 |
lemma %quote powers_power:
|
haftmann@37401
|
49 |
"powers xs \<circ> power x = power x \<circ> powers xs"
|
haftmann@37401
|
50 |
by (induct xs)
|
haftmann@37401
|
51 |
(simp_all del: o_apply id_apply add: o_assoc [symmetric],
|
haftmann@37401
|
52 |
simp del: o_apply add: o_assoc power_commute)
|
haftmann@37401
|
53 |
|
haftmann@37401
|
54 |
lemma %quote powers_rev:
|
haftmann@37401
|
55 |
"powers (rev xs) = powers xs"
|
haftmann@37401
|
56 |
by (induct xs) (simp_all add: powers_append powers_power)
|
haftmann@37401
|
57 |
|
haftmann@37401
|
58 |
end %quote
|
haftmann@37401
|
59 |
|
haftmann@37401
|
60 |
text {*
|
haftmann@37401
|
61 |
After an interpretation of this locale (say, @{command
|
haftmann@37401
|
62 |
interpretation} @{text "fun_power:"} @{term [source] "power (\<lambda>n (f ::
|
haftmann@37401
|
63 |
'a \<Rightarrow> 'a). f ^^ n)"}), one would expect to have a constant @{text
|
haftmann@37401
|
64 |
"fun_power.powers :: nat list \<Rightarrow> ('a \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> 'a"} for which code
|
haftmann@37401
|
65 |
can be generated. But this not the case: internally, the term
|
haftmann@37401
|
66 |
@{text "fun_power.powers"} is an abbreviation for the foundational
|
haftmann@37401
|
67 |
term @{term [source] "power.powers (\<lambda>n (f :: 'a \<Rightarrow> 'a). f ^^ n)"}
|
haftmann@37401
|
68 |
(see \cite{isabelle-locale} for the details behind).
|
haftmann@37401
|
69 |
|
haftmann@37401
|
70 |
Furtunately, with minor effort the desired behaviour can be achieved.
|
haftmann@37401
|
71 |
First, a dedicated definition of the constant on which the local @{text "powers"}
|
haftmann@37401
|
72 |
after interpretation is supposed to be mapped on:
|
haftmann@37401
|
73 |
*}
|
haftmann@37401
|
74 |
|
haftmann@37401
|
75 |
definition %quote funpows :: "nat list \<Rightarrow> ('a \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> 'a" where
|
haftmann@37401
|
76 |
[code del]: "funpows = power.powers (\<lambda>n f. f ^^ n)"
|
haftmann@37401
|
77 |
|
haftmann@37401
|
78 |
text {*
|
haftmann@37401
|
79 |
\noindent In general, the pattern is @{text "c = t"} where @{text c} is
|
haftmann@37401
|
80 |
the name of the future constant and @{text t} the foundational term
|
haftmann@37401
|
81 |
corresponding to the local constant after interpretation.
|
haftmann@37401
|
82 |
|
haftmann@37401
|
83 |
The interpretation itself is enriched with an equation @{text "t = c"}:
|
haftmann@37401
|
84 |
*}
|
haftmann@37401
|
85 |
|
haftmann@37401
|
86 |
interpretation %quote fun_power: power "\<lambda>n (f :: 'a \<Rightarrow> 'a). f ^^ n" where
|
haftmann@37401
|
87 |
"power.powers (\<lambda>n f. f ^^ n) = funpows"
|
haftmann@37401
|
88 |
by unfold_locales
|
haftmann@37401
|
89 |
(simp_all add: expand_fun_eq funpow_mult mult_commute funpows_def)
|
haftmann@37401
|
90 |
|
haftmann@37401
|
91 |
text {*
|
haftmann@37401
|
92 |
\noindent This additional equation is trivially proved by the definition
|
haftmann@37401
|
93 |
itself.
|
haftmann@37401
|
94 |
|
haftmann@37401
|
95 |
After this setup procedure, code generation can continue as usual:
|
haftmann@37401
|
96 |
*}
|
haftmann@37401
|
97 |
|
haftmann@37401
|
98 |
text %quote {*@{code_stmts funpows (consts) Nat.funpow funpows (Haskell)}*}
|
haftmann@37401
|
99 |
|
haftmann@37401
|
100 |
|
haftmann@28419
|
101 |
subsection {* Modules *}
|
haftmann@28419
|
102 |
|
haftmann@28419
|
103 |
text {*
|
haftmann@28419
|
104 |
When invoking the @{command export_code} command it is possible to leave
|
haftmann@28419
|
105 |
out the @{keyword "module_name"} part; then code is distributed over
|
haftmann@28419
|
106 |
different modules, where the module name space roughly is induced
|
haftmann@28635
|
107 |
by the @{text Isabelle} theory name space.
|
haftmann@28419
|
108 |
|
haftmann@28419
|
109 |
Then sometimes the awkward situation occurs that dependencies between
|
haftmann@28419
|
110 |
definitions introduce cyclic dependencies between modules, which in the
|
haftmann@28419
|
111 |
@{text Haskell} world leaves you to the mercy of the @{text Haskell} implementation
|
haftmann@28419
|
112 |
you are using, while for @{text SML}/@{text OCaml} code generation is not possible.
|
haftmann@28419
|
113 |
|
haftmann@28419
|
114 |
A solution is to declare module names explicitly.
|
haftmann@28419
|
115 |
Let use assume the three cyclically dependent
|
haftmann@28419
|
116 |
modules are named \emph{A}, \emph{B} and \emph{C}.
|
haftmann@28419
|
117 |
Then, by stating
|
haftmann@28419
|
118 |
*}
|
haftmann@28419
|
119 |
|
haftmann@28593
|
120 |
code_modulename %quote SML
|
haftmann@28419
|
121 |
A ABC
|
haftmann@28419
|
122 |
B ABC
|
haftmann@28419
|
123 |
C ABC
|
haftmann@28419
|
124 |
|
paulson@34155
|
125 |
text {*\noindent
|
haftmann@28419
|
126 |
we explicitly map all those modules on \emph{ABC},
|
haftmann@28419
|
127 |
resulting in an ad-hoc merge of this three modules
|
haftmann@28419
|
128 |
at serialisation time.
|
haftmann@28419
|
129 |
*}
|
haftmann@28213
|
130 |
|
haftmann@28213
|
131 |
subsection {* Evaluation oracle *}
|
haftmann@28213
|
132 |
|
haftmann@28593
|
133 |
text {*
|
haftmann@28593
|
134 |
Code generation may also be used to \emph{evaluate} expressions
|
haftmann@28593
|
135 |
(using @{text SML} as target language of course).
|
paulson@34155
|
136 |
For instance, the @{command value} reduces an expression to a
|
haftmann@28593
|
137 |
normal form with respect to the underlying code equations:
|
haftmann@28593
|
138 |
*}
|
haftmann@28593
|
139 |
|
haftmann@28593
|
140 |
value %quote "42 / (12 :: rat)"
|
haftmann@28593
|
141 |
|
haftmann@28593
|
142 |
text {*
|
haftmann@28593
|
143 |
\noindent will display @{term "7 / (2 :: rat)"}.
|
haftmann@28593
|
144 |
|
haftmann@28593
|
145 |
The @{method eval} method tries to reduce a goal by code generation to @{term True}
|
haftmann@28593
|
146 |
and solves it in that case, but fails otherwise:
|
haftmann@28593
|
147 |
*}
|
haftmann@28593
|
148 |
|
haftmann@28593
|
149 |
lemma %quote "42 / (12 :: rat) = 7 / 2"
|
haftmann@28593
|
150 |
by %quote eval
|
haftmann@28593
|
151 |
|
haftmann@28593
|
152 |
text {*
|
haftmann@28593
|
153 |
\noindent The soundness of the @{method eval} method depends crucially
|
haftmann@28593
|
154 |
on the correctness of the code generator; this is one of the reasons
|
haftmann@31050
|
155 |
why you should not use adaptation (see \secref{sec:adaptation}) frivolously.
|
haftmann@28593
|
156 |
*}
|
haftmann@28593
|
157 |
|
haftmann@28213
|
158 |
subsection {* Code antiquotation *}
|
haftmann@28213
|
159 |
|
haftmann@28593
|
160 |
text {*
|
haftmann@28593
|
161 |
In scenarios involving techniques like reflection it is quite common
|
haftmann@28593
|
162 |
that code generated from a theory forms the basis for implementing
|
haftmann@28593
|
163 |
a proof procedure in @{text SML}. To facilitate interfacing of generated code
|
haftmann@28593
|
164 |
with system code, the code generator provides a @{text code} antiquotation:
|
haftmann@28593
|
165 |
*}
|
haftmann@28213
|
166 |
|
haftmann@30880
|
167 |
datatype %quote form = T | F | And form form | Or form form (*<*)
|
haftmann@30880
|
168 |
|
haftmann@30880
|
169 |
(*>*) ML %quotett {*
|
haftmann@28593
|
170 |
fun eval_form @{code T} = true
|
haftmann@28593
|
171 |
| eval_form @{code F} = false
|
haftmann@28593
|
172 |
| eval_form (@{code And} (p, q)) =
|
haftmann@28593
|
173 |
eval_form p andalso eval_form q
|
haftmann@28593
|
174 |
| eval_form (@{code Or} (p, q)) =
|
haftmann@28593
|
175 |
eval_form p orelse eval_form q;
|
haftmann@28593
|
176 |
*}
|
haftmann@28593
|
177 |
|
haftmann@28593
|
178 |
text {*
|
haftmann@28593
|
179 |
\noindent @{text code} takes as argument the name of a constant; after the
|
haftmann@28593
|
180 |
whole @{text SML} is read, the necessary code is generated transparently
|
haftmann@28593
|
181 |
and the corresponding constant names are inserted. This technique also
|
haftmann@28593
|
182 |
allows to use pattern matching on constructors stemming from compiled
|
haftmann@37208
|
183 |
@{text "datatypes"}.
|
haftmann@28593
|
184 |
|
haftmann@29733
|
185 |
For a less simplistic example, theory @{theory Ferrack} is
|
haftmann@28593
|
186 |
a good reference.
|
haftmann@28593
|
187 |
*}
|
haftmann@28213
|
188 |
|
haftmann@28419
|
189 |
subsection {* Imperative data structures *}
|
haftmann@28419
|
190 |
|
haftmann@28593
|
191 |
text {*
|
haftmann@28593
|
192 |
If you consider imperative data structures as inevitable for a specific
|
haftmann@28593
|
193 |
application, you should consider
|
haftmann@28593
|
194 |
\emph{Imperative Functional Programming with Isabelle/HOL}
|
paulson@34155
|
195 |
\cite{bulwahn-et-al:2008:imperative};
|
haftmann@28593
|
196 |
the framework described there is available in theory @{theory Imperative_HOL}.
|
haftmann@28593
|
197 |
*}
|
haftmann@28593
|
198 |
|
haftmann@28213
|
199 |
end
|