| author | wenzelm |
| Fri, 22 Oct 2010 11:27:05 +0100 | |
| changeset 39879 | be8a7334e4ec |
| parent 39878 | 31dd361a3060 |
| child 39880 | 7deb6a741626 |
| permissions | -rw-r--r-- |
| 29755 | 1 |
theory "ML" |
2 |
imports Base |
|
3 |
begin |
|
| 18538 | 4 |
|
| 39822 | 5 |
chapter {* Isabelle/ML *}
|
| 20489 | 6 |
|
| 39823 | 7 |
text {* Isabelle/ML is best understood as a certain culture based on
|
8 |
Standard ML. Thus it is not a new programming language, but a |
|
9 |
certain way to use SML at an advanced level within the Isabelle |
|
10 |
environment. This covers a variety of aspects that are geared |
|
11 |
towards an efficient and robust platform for applications of formal |
|
12 |
logic with fully foundational proof construction --- according to |
|
13 |
the well-known \emph{LCF principle}. There are specific library
|
|
14 |
modules and infrastructure to address the needs for such difficult |
|
15 |
tasks. For example, the raw parallel programming model of Poly/ML |
|
16 |
is presented as considerably more abstract concept of \emph{future
|
|
17 |
values}, which is then used to augment the inference kernel, proof |
|
18 |
interpreter, and theory loader accordingly. |
|
19 |
||
20 |
The main aspects of Isabelle/ML are introduced below. These |
|
21 |
first-hand explanations should help to understand how proper |
|
22 |
Isabelle/ML is to be read and written, and to get access to the |
|
23 |
wealth of experience that is expressed in the source text and its |
|
24 |
history of changes.\footnote{See
|
|
25 |
\url{http://isabelle.in.tum.de/repos/isabelle} for the full
|
|
26 |
Mercurial history. There are symbolic tags to refer to official |
|
27 |
Isabelle releases, as opposed to arbitrary \emph{tip} versions that
|
|
28 |
merely reflect snapshots that are never really up-to-date.} *} |
|
29 |
||
30 |
||
| 39878 | 31 |
section {* Style and orthography *}
|
32 |
||
| 39879 | 33 |
text {* The sources of Isabelle/Isar are optimized for
|
34 |
\emph{readability} and \emph{maintainability}. The main purpose is
|
|
35 |
to tell an informed reader what is really going on and how things |
|
36 |
really work. This is a non-trivial aim, but it is supported by a |
|
37 |
certain style of writing Isabelle/ML that has emerged from long |
|
38 |
years of system development.\footnote{See also the interesting style
|
|
39 |
guide for OCaml |
|
| 39878 | 40 |
\url{http://caml.inria.fr/resources/doc/guides/guidelines.en.html}
|
41 |
which shares many of our means and ends.} |
|
42 |
||
43 |
The main principle behind any coding style is \emph{consistency}.
|
|
| 39879 | 44 |
For a single author of a small program this merely means ``choose |
| 39878 | 45 |
your style and stick to it''. A complex project like Isabelle, with |
| 39879 | 46 |
long years of development and different contributors, requires more |
47 |
standardization. A coding style that is changed every few years or |
|
48 |
with every new contributor is no style at all, because consistency |
|
49 |
is quickly lost. Global consistency is hard to achieve, though. |
|
50 |
One should always strife at least for local consistency of modules |
|
51 |
and sub-systems, without deviating from some general principles how |
|
52 |
to write Isabelle/ML. |
|
| 39878 | 53 |
|
54 |
In a sense, a common coding style is like an \emph{orthography} for
|
|
| 39879 | 55 |
the sources: it helps to read quickly over the text and see through |
56 |
the main points, without getting distracted by accidental |
|
57 |
presentation of free-style source. |
|
| 39878 | 58 |
*} |
59 |
||
60 |
||
61 |
subsection {* Header and sectioning *}
|
|
62 |
||
| 39879 | 63 |
text {* Isabelle source files have a certain standardized header
|
64 |
format (with precise spacing) that follows ancient traditions |
|
65 |
reaching back to the earliest versions of the system by Larry |
|
66 |
Paulson. E.g.\ see @{"file" "~~/src/Pure/thm.ML"}.
|
|
| 39878 | 67 |
|
68 |
The header includes at least @{verbatim Title} and @{verbatim
|
|
69 |
Author} entries, followed by a prose description of the purpose of |
|
70 |
the module. The latter can range from a single line to several |
|
71 |
paragraphs of explanations. |
|
72 |
||
73 |
The rest of the file is divided into sections, subsections, |
|
| 39879 | 74 |
subsubsections, paragraphs etc.\ using some a layout via ML comments |
75 |
as follows. |
|
| 39878 | 76 |
|
77 |
\begin{verbatim}
|
|
78 |
(*** section ***) |
|
79 |
||
80 |
(** subsection **) |
|
81 |
||
82 |
(* subsubsection *) |
|
83 |
||
84 |
(*short paragraph*) |
|
85 |
||
86 |
(* |
|
87 |
long paragraph |
|
88 |
more text |
|
89 |
*) |
|
90 |
\end{verbatim}
|
|
91 |
||
92 |
As in regular typography, there is some extra space \emph{before}
|
|
93 |
section headings that are adjacent to plain text (not other headings |
|
94 |
as in the example above). |
|
95 |
||
96 |
\medskip The precise wording of the prose text given in these |
|
| 39879 | 97 |
headings is chosen carefully to indicate the main theme of the |
98 |
subsequent formal ML text. |
|
99 |
*} |
|
100 |
||
101 |
||
102 |
subsection {* Basic naming conventions *}
|
|
103 |
||
104 |
text {* Since ML is the primary medium to express the meaning of the
|
|
105 |
source text, naming of ML entities requires special care. |
|
106 |
||
107 |
FIXME |
|
| 39878 | 108 |
*} |
109 |
||
110 |
||
111 |
subsection {* General source layout *}
|
|
112 |
||
113 |
text {* The general Isabelle/ML source layout imitates regular
|
|
114 |
type-setting to some extent, augmented by the requirements for |
|
115 |
deeply nested expressions that are commonplace in functional |
|
116 |
programming. |
|
117 |
||
118 |
\paragraph{Line length} is 80 characters according to ancient
|
|
| 39879 | 119 |
standards, but we allow as much as 100 characters, not more. This |
120 |
acknowledges extra the space requirements due to qualified library |
|
121 |
references in Isabelle/ML. |
|
| 39878 | 122 |
|
123 |
\paragraph{White-space} is used to emphasize the structure of
|
|
124 |
expressions, following mostly standard conventions for mathematical |
|
125 |
typesetting, as can be seen in plain {\TeX} or {\LaTeX}. This
|
|
| 39879 | 126 |
defines positioning of spaces for parentheses, punctuation, and |
127 |
infixes as illustrated here: |
|
| 39878 | 128 |
|
129 |
\begin{verbatim}
|
|
130 |
val x = y + z * (a + b); |
|
131 |
val pair = (a, b); |
|
132 |
val record = {foo = 1, bar = 2};
|
|
133 |
\end{verbatim}
|
|
134 |
||
| 39879 | 135 |
Lines are normally broken \emph{after} an infix operator or
|
136 |
punctuation character. For example: |
|
| 39878 | 137 |
|
138 |
\begin{verbatim}
|
|
139 |
val x = |
|
140 |
a + |
|
141 |
b + |
|
142 |
c; |
|
143 |
||
144 |
val tuple = |
|
145 |
(a, |
|
146 |
b, |
|
147 |
c); |
|
148 |
\end{verbatim}
|
|
149 |
||
150 |
Some special infixes (e.g.\ @{verbatim "|>"}) work better at the
|
|
| 39879 | 151 |
start of the line, but punctuation is always at the end. |
| 39878 | 152 |
|
153 |
Function application follows the tradition of @{text "\<lambda>"}-calculus,
|
|
154 |
not informal mathematics. For example: @{verbatim "f a b"} for a
|
|
155 |
curried function, or @{verbatim "g (a, b)"} for a tupled function.
|
|
156 |
Note that the space between @{verbatim g} and the pair @{verbatim
|
|
| 39879 | 157 |
"(a, b)"} follows the important principle of |
158 |
\emph{compositionality}: the layout of @{verbatim "g p"} does not
|
|
159 |
change when @{verbatim "p"} is refined to a concrete pair.
|
|
| 39878 | 160 |
|
161 |
\paragraph{Indentation} uses plain spaces, never hard
|
|
162 |
tabulators.\footnote{Tabulators were invented to move the carriage
|
|
163 |
of a type-writer to certain predefined positions. In software they |
|
164 |
could be used as a primitive run-length compression of consecutive |
|
165 |
spaces, but the precise result would depend on non-standardized |
|
166 |
editor configuration.} |
|
167 |
||
| 39879 | 168 |
Each level of nesting is indented by 2 spaces, sometimes 1, very |
169 |
rarely 4, never 8. |
|
| 39878 | 170 |
|
| 39879 | 171 |
Indentation follows a simple logical format that only depends on the |
172 |
nesting depth, not the accidental length of the text that initiates |
|
173 |
a level of nesting. Example: |
|
| 39878 | 174 |
|
175 |
\begin{verbatim}
|
|
| 39879 | 176 |
(*RIGHT*) |
| 39878 | 177 |
if b then |
| 39879 | 178 |
expr1_part1 |
179 |
expr1_part2 |
|
| 39878 | 180 |
else |
| 39879 | 181 |
expr2_part1 |
182 |
expr2_part2 |
|
| 39878 | 183 |
|
| 39879 | 184 |
(*WRONG*) |
185 |
if b then expr1_part1 |
|
186 |
expr1_part2 |
|
187 |
else expr2_part1 |
|
188 |
expr2_part2 |
|
| 39878 | 189 |
\end{verbatim}
|
190 |
||
191 |
The second form has many problems: it assumes a fixed-width font |
|
| 39879 | 192 |
when viewing the sources, it uses more space on the line and thus |
193 |
makes it hard to observe its strict length limit (working against |
|
| 39878 | 194 |
\emph{readability}), it requires extra editing to adapt the layout
|
| 39879 | 195 |
to changes of the initial text (working against |
| 39878 | 196 |
\emph{maintainability}) etc.
|
197 |
||
| 39879 | 198 |
\medskip For similar reasons, any kind of two-dimensional or tabular |
199 |
layouts, ASCII-art with lines or boxes of stars etc. should be |
|
200 |
avoided. |
|
| 39878 | 201 |
*} |
202 |
||
203 |
||
| 39823 | 204 |
section {* SML embedded into Isabelle/Isar *}
|
205 |
||
| 39824 | 206 |
text {* ML and Isar are intertwined via an open-ended bootstrap
|
207 |
process that provides more and more programming facilities and |
|
208 |
logical content in an alternating manner. Bootstrapping starts from |
|
209 |
the raw environment of existing implementations of Standard ML |
|
210 |
(mainly Poly/ML, but also SML/NJ). |
|
| 39823 | 211 |
|
| 39824 | 212 |
Isabelle/Pure marks the point where the original ML toplevel is |
213 |
superseded by the Isar toplevel that maintains a uniform environment |
|
214 |
for arbitrary ML values (see also \secref{sec:context}). This
|
|
215 |
formal context holds logical entities as well as ML compiler |
|
216 |
bindings, among many other things. Raw Standard ML is never |
|
217 |
encountered again after the initial bootstrap of Isabelle/Pure. |
|
| 39823 | 218 |
|
| 39824 | 219 |
Object-logics such as Isabelle/HOL are built within the |
220 |
Isabelle/ML/Isar environment of Pure by introducing suitable |
|
221 |
theories with associated ML text, either inlined or as separate |
|
222 |
files. Thus Isabelle/HOL is defined as a regular user-space |
|
223 |
application within the Isabelle framework. Further add-on tools can |
|
224 |
be implemented in ML within the Isar context in the same manner: ML |
|
225 |
is part of the regular user-space repertoire of Isabelle. |
|
| 39823 | 226 |
*} |
227 |
||
| 39824 | 228 |
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
229 |
subsection {* Isar ML commands *}
|
| 39823 | 230 |
|
231 |
text {* The primary Isar source language provides various facilities
|
|
232 |
to open a ``window'' to the underlying ML compiler. Especially see |
|
| 39824 | 233 |
@{command_ref "use"} and @{command_ref "ML"}, which work exactly the
|
234 |
same way, only the source text is provided via a file vs.\ inlined, |
|
235 |
respectively. Apart from embedding ML into the main theory |
|
236 |
definition like that, there are many more commands that refer to ML |
|
237 |
source, such as @{command_ref setup} or @{command_ref declaration}.
|
|
238 |
An example of even more fine-grained embedding of ML into Isar is |
|
239 |
the proof method @{method_ref tactic}, which refines the pending goal state
|
|
240 |
via a given expression of type @{ML_type tactic}.
|
|
241 |
*} |
|
| 39823 | 242 |
|
| 39824 | 243 |
text %mlex {* The following artificial example demonstrates some ML
|
244 |
toplevel declarations within the implicit Isar theory context. This |
|
245 |
is regular functional programming without referring to logical |
|
246 |
entities yet. |
|
| 39823 | 247 |
*} |
248 |
||
249 |
ML {*
|
|
250 |
fun factorial 0 = 1 |
|
251 |
| factorial n = n * factorial (n - 1) |
|
252 |
*} |
|
253 |
||
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
254 |
text {* Here the ML environment is really managed by Isabelle, i.e.\
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
255 |
the @{ML factorial} function is not yet accessible in the preceding
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
256 |
paragraph, nor in a different theory that is independent from the |
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
257 |
current one in the import hierarchy. |
| 39823 | 258 |
|
259 |
Removing the above ML declaration from the source text will remove |
|
260 |
any trace of this definition as expected. The Isabelle/ML toplevel |
|
261 |
environment is managed in a \emph{stateless} way: unlike the raw ML
|
|
| 39824 | 262 |
toplevel or similar command loops of Computer Algebra systems, there |
263 |
are no global side-effects involved here.\footnote{Such a stateless
|
|
264 |
compilation environment is also a prerequisite for robust parallel |
|
265 |
compilation within independent nodes of the implicit theory |
|
266 |
development graph.} |
|
| 39823 | 267 |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
268 |
\medskip The next example shows how to embed ML into Isar proofs. |
| 39824 | 269 |
Instead of @{command_ref "ML"} for theory mode, we use @{command_ref
|
270 |
"ML_prf"} for proof mode. As illustrated below, its effect on the |
|
271 |
ML environment is local to the whole proof body, while ignoring its |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
272 |
internal block structure. *} |
| 39823 | 273 |
|
274 |
example_proof |
|
| 39851 | 275 |
ML_prf %"ML" {* val a = 1 *}
|
| 39824 | 276 |
{ -- {* Isar block structure ignored by ML environment *}
|
| 39851 | 277 |
ML_prf %"ML" {* val b = a + 1 *}
|
| 39824 | 278 |
} -- {* Isar block structure ignored by ML environment *}
|
| 39851 | 279 |
ML_prf %"ML" {* val c = b + 1 *}
|
| 39823 | 280 |
qed |
281 |
||
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
282 |
text {* By side-stepping the normal scoping rules for Isar proof
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
283 |
blocks, embedded ML code can refer to the different contexts |
| 39824 | 284 |
explicitly, and manipulate corresponding entities, e.g.\ export a |
285 |
fact from a block context. |
|
| 39823 | 286 |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
287 |
\medskip Two further ML commands are useful in certain situations: |
| 39824 | 288 |
@{command_ref ML_val} and @{command_ref ML_command} are both
|
289 |
\emph{diagnostic} in the sense that there is no effect on the
|
|
290 |
underlying environment, and can thus used anywhere (even outside a |
|
291 |
theory). The examples below produce long strings of digits by |
|
292 |
invoking @{ML factorial}: @{command ML_val} already takes care of
|
|
293 |
printing the ML toplevel result, but @{command ML_command} is silent
|
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
294 |
so we produce an explicit output message. *} |
| 39823 | 295 |
|
296 |
ML_val {* factorial 100 *}
|
|
297 |
ML_command {* writeln (string_of_int (factorial 100)) *}
|
|
298 |
||
299 |
example_proof |
|
| 39824 | 300 |
ML_val {* factorial 100 *} (* FIXME check/fix indentation *)
|
| 39823 | 301 |
ML_command {* writeln (string_of_int (factorial 100)) *}
|
302 |
qed |
|
303 |
||
304 |
||
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
305 |
subsection {* Compile-time context *}
|
| 39823 | 306 |
|
|
39825
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
307 |
text {* Whenever the ML compiler is invoked within Isabelle/Isar, the
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
308 |
formal context is passed as a thread-local reference variable. Thus |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
309 |
ML code may access the theory context during compilation, by reading |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
310 |
or writing the (local) theory under construction. Note that such |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
311 |
direct access to the compile-time context is rare; in practice it is |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
312 |
typically via some derived ML functions. |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
313 |
*} |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
314 |
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
315 |
text %mlref {*
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
316 |
\begin{mldecls}
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
317 |
@{index_ML ML_Context.the_generic_context: "unit -> Context.generic"} \\
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
318 |
@{index_ML "Context.>> ": "(Context.generic -> Context.generic) -> unit"} \\
|
| 39850 | 319 |
@{index_ML bind_thms: "string * thm list -> unit"} \\
|
320 |
@{index_ML bind_thm: "string * thm -> unit"} \\
|
|
|
39825
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
321 |
\end{mldecls}
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
322 |
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
323 |
\begin{description}
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
324 |
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
325 |
\item @{ML "ML_Context.the_generic_context ()"} refers to the theory
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
326 |
context of the ML toplevel --- at compile time. ML code needs to |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
327 |
take care to refer to @{ML "ML_Context.the_generic_context ()"}
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
328 |
correctly. Recall that evaluation of a function body is delayed |
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
329 |
until actual run-time. |
|
39825
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
330 |
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
331 |
\item @{ML "Context.>>"}~@{text f} applies context transformation
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
332 |
@{text f} to the implicit context of the ML toplevel.
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
333 |
|
| 39850 | 334 |
\item @{ML bind_thms}~@{text "(name, thms)"} stores a list of
|
335 |
theorems produced in ML both in the (global) theory context and the |
|
336 |
ML toplevel, associating it with the provided name. Theorems are |
|
337 |
put into a global ``standard'' format before being stored. |
|
338 |
||
339 |
\item @{ML bind_thm} is similar to @{ML bind_thms} but refers to a
|
|
340 |
singleton theorem. |
|
341 |
||
|
39825
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
342 |
\end{description}
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
343 |
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
344 |
It is very important to note that the above functions are really |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
345 |
restricted to the compile time, even though the ML compiler is |
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
346 |
invoked at run-time. The majority of ML code either uses static |
|
39825
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
347 |
antiquotations (\secref{sec:ML-antiq}) or refers to the theory or
|
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
348 |
proof context at run-time, by explicit functional abstraction. |
|
f9066b94bf07
eliminated fancy \ML logo for the sake of simpler source text (less dependence on LaTeX);
wenzelm
parents:
39824
diff
changeset
|
349 |
*} |
| 39823 | 350 |
|
351 |
||
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
352 |
subsection {* Antiquotations \label{sec:ML-antiq} *}
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
353 |
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
354 |
text {* A very important consequence of embedding SML into Isar is the
|
| 39829 | 355 |
concept of \emph{ML antiquotation}. First, the standard token
|
356 |
language of ML is augmented by special syntactic entities of the |
|
357 |
following form: |
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
358 |
|
| 39829 | 359 |
\indexouternonterm{antiquote}
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
360 |
\begin{rail}
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
361 |
antiquote: atsign lbrace nameref args rbrace | lbracesym | rbracesym |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
362 |
; |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
363 |
\end{rail}
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
364 |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
365 |
Here @{syntax nameref} and @{syntax args} are regular outer syntax
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
366 |
categories. Note that attributes and proof methods use similar |
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
367 |
syntax. |
| 39823 | 368 |
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
369 |
\medskip A regular antiquotation @{text "@{name args}"} processes
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
370 |
its arguments by the usual means of the Isar source language, and |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
371 |
produces corresponding ML source text, either as literal |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
372 |
\emph{inline} text (e.g. @{text "@{term t}"}) or abstract
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
373 |
\emph{value} (e.g. @{text "@{thm th}"}). This pre-compilation
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
374 |
scheme allows to refer to formal entities in a robust manner, with |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
375 |
proper static scoping and with some degree of logical checking of |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
376 |
small portions of the code. |
| 39823 | 377 |
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
378 |
Special antiquotations like @{text "@{let \<dots>}"} or @{text "@{note
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
379 |
\<dots>}"} augment the compilation context without generating code. The |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
380 |
non-ASCII braces @{text "\<lbrace>"} and @{text "\<rbrace>"} allow to delimit the
|
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
381 |
effect by introducing local blocks within the pre-compilation |
|
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
382 |
environment. |
| 39829 | 383 |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
384 |
\medskip See also \cite{Wenzel-Chaieb:2007b} for a slightly broader
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
385 |
perspective on Isabelle/ML antiquotations. *} |
| 39829 | 386 |
|
| 39830 | 387 |
text %mlantiq {*
|
| 39829 | 388 |
\begin{matharray}{rcl}
|
389 |
@{ML_antiquotation_def "let"} & : & @{text ML_antiquotation} \\
|
|
390 |
@{ML_antiquotation_def "note"} & : & @{text ML_antiquotation} \\
|
|
391 |
\end{matharray}
|
|
392 |
||
393 |
\begin{rail}
|
|
394 |
'let' ((term + 'and') '=' term + 'and') |
|
395 |
; |
|
396 |
||
397 |
'note' (thmdef? thmrefs + 'and') |
|
398 |
; |
|
399 |
\end{rail}
|
|
400 |
||
401 |
\begin{description}
|
|
402 |
||
403 |
\item @{text "@{let p = t}"} binds schematic variables in the
|
|
404 |
pattern @{text "p"} by higher-order matching against the term @{text
|
|
405 |
"t"}. This is analogous to the regular @{command_ref let} command
|
|
406 |
in the Isar proof language. The pre-compilation environment is |
|
407 |
augmented by auxiliary term bindings, without emitting ML source. |
|
408 |
||
409 |
\item @{text "@{note a = b\<^sub>1 \<dots> b\<^sub>n}"} recalls existing facts @{text
|
|
410 |
"b\<^sub>1, \<dots>, b\<^sub>n"}, binding the result as @{text a}. This is analogous to
|
|
411 |
the regular @{command_ref note} command in the Isar proof language.
|
|
412 |
The pre-compilation environment is augmented by auxiliary fact |
|
413 |
bindings, without emitting ML source. |
|
414 |
||
415 |
\end{description}
|
|
416 |
*} |
|
417 |
||
418 |
text %mlex {* The following artificial example gives a first
|
|
419 |
impression about using the antiquotation elements introduced so far, |
|
420 |
together with the basic @{text "@{thm}"} antiquotation defined
|
|
421 |
later. |
|
422 |
*} |
|
423 |
||
424 |
ML {*
|
|
425 |
\<lbrace> |
|
426 |
@{let ?t = my_term}
|
|
427 |
@{note my_refl = reflexive [of ?t]}
|
|
428 |
fun foo th = Thm.transitive th @{thm my_refl}
|
|
429 |
\<rbrace> |
|
430 |
*} |
|
431 |
||
432 |
text {*
|
|
433 |
The extra block delimiters do not affect the compiled code itself, i.e.\ |
|
434 |
function @{ML foo} is available in the present context.
|
|
|
39827
d829ce302ca4
basic setup for ML antiquotations -- with rail diagrams;
wenzelm
parents:
39825
diff
changeset
|
435 |
*} |
| 39823 | 436 |
|
| 39835 | 437 |
|
| 39854 | 438 |
section {* Message output channels \label{sec:message-channels} *}
|
| 39835 | 439 |
|
440 |
text {* Isabelle provides output channels for different kinds of
|
|
441 |
messages: regular output, high-volume tracing information, warnings, |
|
442 |
and errors. |
|
443 |
||
444 |
Depending on the user interface involved, these messages may appear |
|
445 |
in different text styles or colours. The standard output for |
|
446 |
terminal sessions prefixes each line of warnings by @{verbatim
|
|
447 |
"###"} and errors by @{verbatim "***"}, but leaves anything else
|
|
448 |
unchanged. |
|
449 |
||
450 |
Messages are associated with the transaction context of the running |
|
451 |
Isar command. This enables the front-end to manage commands and |
|
452 |
resulting messages together. For example, after deleting a command |
|
453 |
from a given theory document version, the corresponding message |
|
| 39872 | 454 |
output can be retracted from the display. |
455 |
*} |
|
| 39835 | 456 |
|
457 |
text %mlref {*
|
|
458 |
\begin{mldecls}
|
|
459 |
@{index_ML writeln: "string -> unit"} \\
|
|
460 |
@{index_ML tracing: "string -> unit"} \\
|
|
461 |
@{index_ML warning: "string -> unit"} \\
|
|
462 |
@{index_ML error: "string -> 'a"} \\
|
|
463 |
\end{mldecls}
|
|
464 |
||
465 |
\begin{description}
|
|
466 |
||
467 |
\item @{ML writeln}~@{text "text"} outputs @{text "text"} as regular
|
|
468 |
message. This is the primary message output operation of Isabelle |
|
469 |
and should be used by default. |
|
470 |
||
471 |
\item @{ML tracing}~@{text "text"} outputs @{text "text"} as special
|
|
472 |
tracing message, indicating potential high-volume output to the |
|
473 |
front-end (hundreds or thousands of messages issued by a single |
|
474 |
command). The idea is to allow the user-interface to downgrade the |
|
475 |
quality of message display to achieve higher throughput. |
|
476 |
||
477 |
Note that the user might have to take special actions to see tracing |
|
478 |
output, e.g.\ switch to a different output window. So this channel |
|
479 |
should not be used for regular output. |
|
480 |
||
481 |
\item @{ML warning}~@{text "text"} outputs @{text "text"} as
|
|
482 |
warning, which typically means some extra emphasis on the front-end |
|
483 |
side (color highlighting, icon). |
|
484 |
||
485 |
\item @{ML error}~@{text "text"} raises exception @{ML ERROR}~@{text
|
|
486 |
"text"} and thus lets the Isar toplevel print @{text "text"} on the
|
|
487 |
error channel, which typically means some extra emphasis on the |
|
488 |
front-end side (color highlighting, icon). |
|
489 |
||
490 |
This assumes that the exception is not handled before the command |
|
491 |
terminates. Handling exception @{ML ERROR}~@{text "text"} is a
|
|
492 |
perfectly legal alternative: it means that the error is absorbed |
|
493 |
without any message output. |
|
494 |
||
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
495 |
\begin{warn}
|
| 39835 | 496 |
The actual error channel is accessed via @{ML Output.error_msg}, but
|
497 |
the interaction protocol of Proof~General \emph{crashes} if that
|
|
498 |
function is used in regular ML code: error output and toplevel |
|
499 |
command failure always need to coincide here. |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
500 |
\end{warn}
|
| 39835 | 501 |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
502 |
\end{description}
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
503 |
|
|
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
504 |
\begin{warn}
|
| 39835 | 505 |
Regular Isabelle/ML code should output messages exclusively by the |
506 |
official channels. Using raw I/O on \emph{stdout} or \emph{stderr}
|
|
507 |
instead (e.g.\ via @{ML TextIO.output}) is apt to cause problems in
|
|
508 |
the presence of parallel and asynchronous processing of Isabelle |
|
509 |
theories. Such raw output might be displayed by the front-end in |
|
510 |
some system console log, with a low chance that the user will ever |
|
511 |
see it. Moreover, as a genuine side-effect on global process |
|
512 |
channels, there is no proper way to retract output when Isar command |
|
513 |
transactions are reset. |
|
|
39861
b8d89db3e238
use continental paragraph style, which works better with mixture of (in)formal text;
wenzelm
parents:
39859
diff
changeset
|
514 |
\end{warn}
|
| 39872 | 515 |
|
516 |
\begin{warn}
|
|
517 |
The message channels should be used in a message-oriented manner. |
|
518 |
This means that multi-line output that logically belongs together |
|
519 |
needs to be issued by a \emph{single} invocation of @{ML writeln}
|
|
520 |
etc. with the functional concatenation of all message constituents. |
|
521 |
\end{warn}
|
|
522 |
*} |
|
523 |
||
524 |
text %mlex {* The following example demonstrates a multi-line
|
|
525 |
warning. Note that in some situations the user sees only the first |
|
526 |
line, so the most important point should be made first. |
|
527 |
*} |
|
528 |
||
529 |
ML_command {*
|
|
530 |
warning (cat_lines |
|
531 |
["Beware the Jabberwock, my son!", |
|
532 |
"The jaws that bite, the claws that catch!", |
|
533 |
"Beware the Jubjub Bird, and shun", |
|
534 |
"The frumious Bandersnatch!"]); |
|
| 39835 | 535 |
*} |
536 |
||
| 39854 | 537 |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
538 |
section {* Exceptions \label{sec:exceptions} *}
|
| 39854 | 539 |
|
540 |
text {* The Standard ML semantics of strict functional evaluation
|
|
541 |
together with exceptions is rather well defined, but some delicate |
|
542 |
points need to be observed to avoid that ML programs go wrong |
|
543 |
despite static type-checking. Exceptions in Isabelle/ML are |
|
544 |
subsequently categorized as follows. |
|
545 |
||
546 |
\paragraph{Regular user errors.} These are meant to provide
|
|
547 |
informative feedback about malformed input etc. |
|
548 |
||
549 |
The \emph{error} function raises the corresponding \emph{ERROR}
|
|
550 |
exception, with a plain text message as argument. \emph{ERROR}
|
|
551 |
exceptions can be handled internally, in order to be ignored, turned |
|
552 |
into other exceptions, or cascaded by appending messages. If the |
|
553 |
corresponding Isabelle/Isar command terminates with an \emph{ERROR}
|
|
| 39855 | 554 |
exception state, the toplevel will print the result on the error |
555 |
channel (see \secref{sec:message-channels}).
|
|
| 39854 | 556 |
|
557 |
It is considered bad style to refer to internal function names or |
|
558 |
values in ML source notation in user error messages. |
|
559 |
||
560 |
Grammatical correctness of error messages can be improved by |
|
561 |
\emph{omitting} final punctuation: messages are often concatenated
|
|
562 |
or put into a larger context (e.g.\ augmented with source position). |
|
563 |
By not insisting in the final word at the origin of the error, the |
|
564 |
system can perform its administrative tasks more easily and |
|
565 |
robustly. |
|
566 |
||
567 |
\paragraph{Program failures.} There is a handful of standard
|
|
568 |
exceptions that indicate general failure situations, or failures of |
|
569 |
core operations on logical entities (types, terms, theorems, |
|
| 39856 | 570 |
theories, see \chref{ch:logic}).
|
| 39854 | 571 |
|
572 |
These exceptions indicate a genuine breakdown of the program, so the |
|
573 |
main purpose is to determine quickly what has happened where. |
|
| 39855 | 574 |
Traditionally, the (short) exception message would include the name |
575 |
of an ML function, although this no longer necessary, because the ML |
|
576 |
runtime system prints a detailed source position of the |
|
577 |
corresponding @{verbatim raise} keyword.
|
|
| 39854 | 578 |
|
579 |
\medskip User modules can always introduce their own custom |
|
580 |
exceptions locally, e.g.\ to organize internal failures robustly |
|
581 |
without overlapping with existing exceptions. Exceptions that are |
|
582 |
exposed in module signatures require extra care, though, and should |
|
583 |
\emph{not} be introduced by default. Surprise by end-users or ML
|
|
| 39855 | 584 |
users of a module can be often minimized by using plain user errors. |
| 39854 | 585 |
|
586 |
\paragraph{Interrupts.} These indicate arbitrary system events:
|
|
587 |
both the ML runtime system and the Isabelle/ML infrastructure signal |
|
588 |
various exceptional situations by raising the special |
|
589 |
\emph{Interrupt} exception in user code.
|
|
590 |
||
591 |
This is the one and only way that physical events can intrude an |
|
592 |
Isabelle/ML program. Such an interrupt can mean out-of-memory, |
|
593 |
stack overflow, timeout, internal signaling of threads, or the user |
|
| 39855 | 594 |
producing a console interrupt manually etc. An Isabelle/ML program |
595 |
that intercepts interrupts becomes dependent on physical effects of |
|
596 |
the environment. Even worse, exception handling patterns that are |
|
597 |
too general by accident, e.g.\ by mispelled exception constructors, |
|
598 |
will cover interrupts unintentionally, and thus render the program |
|
599 |
semantics ill-defined. |
|
| 39854 | 600 |
|
601 |
Note that the Interrupt exception dates back to the original SML90 |
|
602 |
language definition. It was excluded from the SML97 version to |
|
603 |
avoid its malign impact on ML program semantics, but without |
|
604 |
providing a viable alternative. Isabelle/ML recovers physical |
|
605 |
interruptibility (which an indispensable tool to implement managed |
|
606 |
evaluation of Isar command transactions), but requires user code to |
|
607 |
be strictly transparent wrt.\ interrupts. |
|
608 |
||
609 |
\begin{warn}
|
|
610 |
Isabelle/ML user code needs to terminate promptly on interruption, |
|
611 |
without guessing at its meaning to the system infrastructure. |
|
612 |
Temporary handling of interrupts for cleanup of global resources |
|
613 |
etc.\ needs to be followed immediately by re-raising of the original |
|
614 |
exception. |
|
615 |
\end{warn}
|
|
616 |
*} |
|
617 |
||
| 39855 | 618 |
text %mlref {*
|
619 |
\begin{mldecls}
|
|
620 |
@{index_ML try: "('a -> 'b) -> 'a -> 'b option"} \\
|
|
621 |
@{index_ML can: "('a -> 'b) -> 'a -> bool"} \\
|
|
| 39856 | 622 |
@{index_ML ERROR: "string -> exn"} \\
|
623 |
@{index_ML Fail: "string -> exn"} \\
|
|
624 |
@{index_ML Exn.is_interrupt: "exn -> bool"} \\
|
|
| 39855 | 625 |
@{index_ML reraise: "exn -> 'a"} \\
|
626 |
@{index_ML exception_trace: "(unit -> 'a) -> 'a"} \\
|
|
627 |
\end{mldecls}
|
|
628 |
||
629 |
\begin{description}
|
|
630 |
||
631 |
\item @{ML try}~@{text "f x"} makes the partiality of evaluating
|
|
632 |
@{text "f x"} explicit via the option datatype. Interrupts are
|
|
633 |
\emph{not} handled here, i.e.\ this form serves as safe replacement
|
|
634 |
for the \emph{unsafe} version @{verbatim "(SOME"}~@{text "f
|
|
635 |
x"}~@{verbatim "handle _ => NONE)"} that is occasionally seen in
|
|
636 |
books about SML. |
|
637 |
||
638 |
\item @{ML can} is similar to @{ML try} with more abstract result.
|
|
639 |
||
| 39856 | 640 |
\item @{ML ERROR}~@{text "msg"} represents user errors; this
|
641 |
exception is always raised via the @{ML error} function (see
|
|
642 |
\secref{sec:message-channels}).
|
|
643 |
||
644 |
\item @{ML Fail}~@{text "msg"} represents general program failures.
|
|
645 |
||
646 |
\item @{ML Exn.is_interrupt} identifies interrupts robustly, without
|
|
647 |
mentioning concrete exception constructors in user code. Handled |
|
648 |
interrupts need to be re-raised promptly! |
|
649 |
||
| 39855 | 650 |
\item @{ML reraise}~@{text "exn"} raises exception @{text "exn"}
|
651 |
while preserving its implicit position information (if possible, |
|
652 |
depending on the ML platform). |
|
653 |
||
654 |
\item @{ML exception_trace}~@{verbatim "(fn _ =>"}~@{text
|
|
655 |
"e"}@{verbatim ")"} evaluates expression @{text "e"} while printing
|
|
656 |
a full trace of its stack of nested exceptions (if possible, |
|
657 |
depending on the ML platform).\footnote{In various versions of
|
|
658 |
Poly/ML the trace will appear on raw stdout of the Isabelle |
|
659 |
process.} |
|
660 |
||
661 |
Inserting @{ML exception_trace} into ML code temporarily is useful
|
|
662 |
for debugging, but not suitable for production code. |
|
663 |
||
664 |
\end{description}
|
|
665 |
*} |
|
666 |
||
|
39866
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
667 |
text %mlantiq {*
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
668 |
\begin{matharray}{rcl}
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
669 |
@{ML_antiquotation_def "assert"} & : & @{text ML_antiquotation} \\
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
670 |
\end{matharray}
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
671 |
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
672 |
\begin{description}
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
673 |
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
674 |
\item @{text "@{assert}"} inlines a function @{text "bool \<Rightarrow> unit"}
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
675 |
that raises @{ML Fail} if the argument is @{ML false}. Due to
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
676 |
inlining the source position of failed assertions is included in the |
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
677 |
error output. |
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
678 |
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
679 |
\end{description}
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
680 |
*} |
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
681 |
|
| 39859 | 682 |
|
| 39863 | 683 |
section {* Basic data types *}
|
| 39859 | 684 |
|
685 |
text {* The basis library proposal of SML97 need to be treated with
|
|
686 |
caution. Many of its operations simply do not fit with important |
|
687 |
Isabelle/ML conventions (like ``canonical argument order'', see |
|
688 |
\secref{sec:canonical-argument-order}), others can cause serious
|
|
689 |
problems with the parallel evaluation model of Isabelle/ML (such as |
|
690 |
@{ML TextIO.print} or @{ML OS.Process.system}).
|
|
691 |
||
692 |
Subsequently we give a brief overview of important operations on |
|
693 |
basic ML data types. |
|
694 |
*} |
|
695 |
||
696 |
||
| 39863 | 697 |
subsection {* Characters *}
|
698 |
||
699 |
text %mlref {*
|
|
700 |
\begin{mldecls}
|
|
701 |
@{index_ML_type char} \\
|
|
702 |
\end{mldecls}
|
|
703 |
||
704 |
\begin{description}
|
|
705 |
||
| 39864 | 706 |
\item Type @{ML_type char} is \emph{not} used. The smallest textual
|
707 |
unit in Isabelle is represented a ``symbol'' (see |
|
708 |
\secref{sec:symbols}).
|
|
| 39863 | 709 |
|
710 |
\end{description}
|
|
711 |
*} |
|
712 |
||
713 |
||
| 39862 | 714 |
subsection {* Integers *}
|
715 |
||
716 |
text %mlref {*
|
|
717 |
\begin{mldecls}
|
|
718 |
@{index_ML_type int} \\
|
|
719 |
\end{mldecls}
|
|
720 |
||
721 |
\begin{description}
|
|
722 |
||
| 39864 | 723 |
\item Type @{ML_type int} represents regular mathematical integers,
|
724 |
which are \emph{unbounded}. Overflow never happens in
|
|
| 39862 | 725 |
practice.\footnote{The size limit for integer bit patterns in memory
|
726 |
is 64\,MB for 32-bit Poly/ML, and much higher for 64-bit systems.} |
|
727 |
This works uniformly for all supported ML platforms (Poly/ML and |
|
728 |
SML/NJ). |
|
729 |
||
730 |
Literal integers in ML text (e.g.\ @{ML
|
|
731 |
123456789012345678901234567890}) are forced to be of this one true |
|
732 |
integer type --- overloading of SML97 is disabled. |
|
733 |
||
734 |
Structure @{ML_struct IntInf} of SML97 is obsolete, always use
|
|
735 |
@{ML_struct Int}. Structure @{ML_struct Integer} in @{"file"
|
|
736 |
"~~/src/Pure/General/integer.ML"} provides some additional |
|
737 |
operations. |
|
738 |
||
739 |
\end{description}
|
|
740 |
*} |
|
741 |
||
742 |
||
| 39859 | 743 |
subsection {* Options *}
|
744 |
||
745 |
text %mlref {*
|
|
746 |
\begin{mldecls}
|
|
747 |
@{index_ML Option.map: "('a -> 'b) -> 'a option -> 'b option"} \\
|
|
748 |
@{index_ML is_some: "'a option -> bool"} \\
|
|
749 |
@{index_ML is_none: "'a option -> bool"} \\
|
|
750 |
@{index_ML the: "'a option -> 'a"} \\
|
|
751 |
@{index_ML these: "'a list option -> 'a list"} \\
|
|
752 |
@{index_ML the_list: "'a option -> 'a list"} \\
|
|
753 |
@{index_ML the_default: "'a -> 'a option -> 'a"} \\
|
|
754 |
\end{mldecls}
|
|
755 |
*} |
|
756 |
||
757 |
text {* Apart from @{ML Option.map} most operations defined in
|
|
758 |
structure @{ML_struct Option} are alien to Isabelle/ML. The
|
|
759 |
operations shown above are defined in @{"file"
|
|
760 |
"~~/src/Pure/General/basics.ML"}, among others. *} |
|
761 |
||
762 |
||
| 39863 | 763 |
subsection {* Lists *}
|
764 |
||
765 |
text {* Lists are ubiquitous in ML as simple and light-weight
|
|
766 |
``collections'' for many everyday programming tasks. Isabelle/ML |
|
| 39874 | 767 |
provides important additions and improvements over operations that |
768 |
are predefined in the SML97 library. *} |
|
| 39863 | 769 |
|
770 |
text %mlref {*
|
|
771 |
\begin{mldecls}
|
|
772 |
@{index_ML cons: "'a -> 'a list -> 'a list"} \\
|
|
| 39874 | 773 |
@{index_ML member: "('b * 'a -> bool) -> 'a list -> 'b -> bool"} \\
|
774 |
@{index_ML insert: "('a * 'a -> bool) -> 'a -> 'a list -> 'a list"} \\
|
|
775 |
@{index_ML remove: "('b * 'a -> bool) -> 'b -> 'a list -> 'a list"} \\
|
|
776 |
@{index_ML update: "('a * 'a -> bool) -> 'a -> 'a list -> 'a list"} \\
|
|
| 39863 | 777 |
\end{mldecls}
|
778 |
||
779 |
\begin{description}
|
|
780 |
||
781 |
\item @{ML cons}~@{text "x xs"} evaluates to @{text "x :: xs"}.
|
|
782 |
||
783 |
Tupled infix operators are a historical accident in Standard ML. |
|
784 |
The curried @{ML cons} amends this, but it should be only used when
|
|
785 |
partial application is required. |
|
786 |
||
| 39874 | 787 |
\item @{ML member}, @{ML insert}, @{ML remove}, @{ML update} treat
|
788 |
lists as a set-like container that maintains the order of elements. |
|
789 |
See @{"file" "~~/src/Pure/library.ML"} for the full specifications
|
|
790 |
(written in ML). There are some further derived operations like |
|
791 |
@{ML union} or @{ML inter}.
|
|
792 |
||
793 |
Note that @{ML insert} is conservative about elements that are
|
|
794 |
already a @{ML member} of the list, while @{ML update} ensures that
|
|
795 |
the last entry is always put in front. The latter discipline is |
|
796 |
often more appropriate in declarations of context data |
|
797 |
(\secref{sec:context-data}) that are issued by the user in Isar
|
|
798 |
source: more recent declarations normally take precedence over |
|
799 |
earlier ones. |
|
800 |
||
| 39863 | 801 |
\end{description}
|
802 |
*} |
|
803 |
||
| 39874 | 804 |
text %mlex {* The following example demonstrates how to \emph{merge}
|
805 |
two lists in a natural way. *} |
|
| 39863 | 806 |
|
| 39874 | 807 |
ML {*
|
808 |
fun merge_lists eq (xs, ys) = fold_rev (insert eq) ys xs; |
|
809 |
*} |
|
810 |
||
811 |
text {* Here the first list is treated conservatively: only the new
|
|
812 |
elements from the second list are inserted. The inside-out order of |
|
813 |
insertion via @{ML fold_rev} attempts to preserve the order of
|
|
814 |
elements in the result. |
|
815 |
||
816 |
This way of merging lists is typical for context data |
|
817 |
(\secref{sec:context-data}). See also @{ML merge} as defined in
|
|
818 |
@{"file" "~~/src/Pure/library.ML"}.
|
|
819 |
*} |
|
820 |
||
821 |
||
822 |
subsubsection {* Canonical iteration *} (* FIXME move!? *)
|
|
| 39863 | 823 |
|
824 |
text {* A function @{text "f: \<alpha> \<rightarrow> \<beta> \<rightarrow> \<beta>"} can be understood as update
|
|
825 |
on a configuration of type @{text "\<beta>"} that is parametrized by
|
|
826 |
arguments of type @{text "\<alpha>"}. Given @{text "a: \<alpha>"} the partial
|
|
827 |
application @{text "(f a): \<beta> \<rightarrow> \<beta>"} operates homogeneously on @{text
|
|
828 |
"\<beta>"}. This can be iterated naturally over a list of parameters |
|
829 |
@{text "[a\<^sub>1, \<dots>, a\<^sub>n]"} as @{text "f a\<^sub>1; \<dots>; f a\<^bsub>n\<^esub>\<^bsub>\<^esub>"} (where the
|
|
830 |
semicolon represents left-to-right composition). The latter |
|
831 |
expression is again a function @{text "\<beta> \<rightarrow> \<beta>"}. It can be applied
|
|
832 |
to an initial configuration @{text "b: \<beta>"} to start the iteration
|
|
833 |
over the given list of arguments: each @{text "a"} in @{text "a\<^sub>1, \<dots>,
|
|
834 |
a\<^sub>n"} is applied consecutively by updating a cumulative |
|
835 |
configuration. |
|
836 |
||
837 |
The @{text fold} combinator in Isabelle/ML lifts a function @{text
|
|
838 |
"f"} as above to its iterated version over a list of arguments. |
|
839 |
Lifting can be repeated, e.g.\ @{text "(fold \<circ> fold) f"} iterates
|
|
840 |
over a list of lists as expected. |
|
841 |
||
842 |
The variant @{text "fold_rev"} works inside-out over the list of
|
|
843 |
arguments, such that @{text "fold_rev f \<equiv> fold f \<circ> rev"} holds.
|
|
844 |
||
845 |
The @{text "fold_map"} combinator essentially performs @{text
|
|
846 |
"fold"} and @{text "map"} simultaneously: each application of @{text
|
|
847 |
"f"} produces an updated configuration together with a side-result; |
|
848 |
the iteration collects all such side-results as a separate list. |
|
849 |
*} |
|
850 |
||
851 |
text %mlref {*
|
|
852 |
\begin{mldecls}
|
|
853 |
@{index_ML fold: "('a -> 'b -> 'b) -> 'a list -> 'b -> 'b"} \\
|
|
854 |
@{index_ML fold_rev: "('a -> 'b -> 'b) -> 'a list -> 'b -> 'b"} \\
|
|
855 |
@{index_ML fold_map: "('a -> 'b -> 'c * 'b) -> 'a list -> 'b -> 'c list * 'b"} \\
|
|
856 |
\end{mldecls}
|
|
857 |
||
858 |
\begin{description}
|
|
859 |
||
860 |
\item @{ML fold}~@{text f} lifts the parametrized update function
|
|
861 |
@{text "f"} to a list of parameters.
|
|
862 |
||
863 |
\item @{ML fold_rev}~@{text "f"} is similar to @{ML fold}~@{text
|
|
864 |
"f"}, but works inside-out. |
|
865 |
||
866 |
\item @{ML fold_map}~@{text "f"} lifts the parametrized update
|
|
867 |
function @{text "f"} (with side-result) to a list of parameters and
|
|
868 |
cumulative side-results. |
|
869 |
||
870 |
\end{description}
|
|
871 |
||
872 |
\begin{warn}
|
|
873 |
The literature on functional programming provides a multitude of |
|
874 |
combinators called @{text "foldl"}, @{text "foldr"} etc. SML97
|
|
875 |
provides its own variations as @{ML List.foldl} and @{ML
|
|
876 |
List.foldr}, while the classic Isabelle library still has the |
|
877 |
slightly more convenient historic @{ML Library.foldl} and @{ML
|
|
878 |
Library.foldr}. To avoid further confusion, all of this should be |
|
879 |
ignored, and @{ML fold} (or @{ML fold_rev}) used exclusively.
|
|
880 |
\end{warn}
|
|
881 |
*} |
|
882 |
||
883 |
text %mlex {* Using canonical @{ML fold} together with canonical @{ML
|
|
884 |
cons}, or similar standard operations, alternates the orientation of |
|
885 |
data. The is quite natural and should not altered forcible by |
|
886 |
inserting extra applications @{ML rev}. The alternative @{ML
|
|
887 |
fold_rev} can be used in the relatively few situations, where |
|
888 |
alternation should be prevented. |
|
889 |
*} |
|
890 |
||
891 |
ML {*
|
|
892 |
val items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
|
893 |
||
894 |
val list1 = fold cons items []; |
|
|
39866
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
895 |
@{assert} (list1 = rev items);
|
|
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
896 |
|
| 39863 | 897 |
val list2 = fold_rev cons items []; |
|
39866
5ec01d5acd0c
more robust examples: explicit @{assert} instead of unchecked output;
wenzelm
parents:
39864
diff
changeset
|
898 |
@{assert} (list2 = items);
|
| 39863 | 899 |
*} |
900 |
||
901 |
||
|
39875
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
902 |
subsection {* Association lists *}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
903 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
904 |
text {* The operations for association lists interpret a concrete list
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
905 |
of pairs as a finite function from keys to values. Redundant |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
906 |
representations with multiple occurrences of the same key are |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
907 |
implicitly normalized: lookup and update only take the first |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
908 |
occurrence into account. |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
909 |
*} |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
910 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
911 |
text {*
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
912 |
\begin{mldecls}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
913 |
@{index_ML AList.lookup: "('a * 'b -> bool) -> ('b * 'c) list -> 'a -> 'c option"} \\
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
914 |
@{index_ML AList.defined: "('a * 'b -> bool) -> ('b * 'c) list -> 'a -> bool"} \\
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
915 |
@{index_ML AList.update: "('a * 'a -> bool) -> 'a * 'b -> ('a * 'b) list -> ('a * 'b) list"} \\
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
916 |
\end{mldecls}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
917 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
918 |
\begin{description}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
919 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
920 |
\item @{ML AList.lookup}, @{ML AList.defined}, @{ML AList.update}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
921 |
implement the main ``framework operations'' for mappings in |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
922 |
Isabelle/ML, with standard conventions for names and types. |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
923 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
924 |
Note that a function called @{text lookup} is obliged to express its
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
925 |
partiality via an explicit option element. There is no choice to |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
926 |
raise an exception, without changing the name to something like |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
927 |
@{text "the_element"} or @{text "get"}.
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
928 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
929 |
The @{text "defined"} operation is essentially a contraction of @{ML
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
930 |
is_some} and @{text "lookup"}, but this is sufficiently frequent to
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
931 |
justify its independent existence. This also gives the |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
932 |
implementation some opportunity for peep-hole optimization. |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
933 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
934 |
\end{description}
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
935 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
936 |
Association lists are adequate as simple and light-weight |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
937 |
implementation of finite mappings in many practical situations. A |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
938 |
more heavy-duty table structure is defined in @{"file"
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
939 |
"~~/src/Pure/General/table.ML"}; that version scales easily to |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
940 |
thousands or millions of elements. |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
941 |
*} |
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
942 |
|
|
648c930125f6
more on "Association lists", based on more succinct version of older material;
wenzelm
parents:
39874
diff
changeset
|
943 |
|
| 39859 | 944 |
subsection {* Unsynchronized references *}
|
945 |
||
946 |
text %mlref {*
|
|
947 |
\begin{mldecls}
|
|
| 39870 | 948 |
@{index_ML_type "'a Unsynchronized.ref"} \\
|
| 39859 | 949 |
@{index_ML Unsynchronized.ref: "'a -> 'a Unsynchronized.ref"} \\
|
950 |
@{index_ML "!": "'a Unsynchronized.ref -> 'a"} \\
|
|
951 |
@{index_ML "op :=": "'a Unsynchronized.ref * 'a -> unit"} \\
|
|
952 |
\end{mldecls}
|
|
953 |
*} |
|
954 |
||
955 |
text {* Due to ubiquitous parallelism in Isabelle/ML (see also
|
|
956 |
\secref{sec:multi-threading}), the mutable reference cells of
|
|
957 |
Standard ML are notorious for causing problems. In a highly |
|
958 |
parallel system, both correctness \emph{and} performance are easily
|
|
959 |
degraded when using mutable data. |
|
960 |
||
961 |
The unwieldy name of @{ML Unsynchronized.ref} for the constructor
|
|
962 |
for references in Isabelle/ML emphasizes the inconveniences caused by |
|
963 |
mutability. Existing operations @{ML "!"} and @{ML "op :="} are
|
|
964 |
unchanged, but should be used with special precautions, say in a |
|
965 |
strictly local situation that is guaranteed to be restricted to |
|
| 39870 | 966 |
sequential evaluation --- now and in the future. *} |
| 39859 | 967 |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
968 |
|
| 39870 | 969 |
section {* Thread-safe programming \label{sec:multi-threading} *}
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
970 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
971 |
text {* Multi-threaded execution has become an everyday reality in
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
972 |
Isabelle since Poly/ML 5.2.1 and Isabelle2008. Isabelle/ML provides |
| 39868 | 973 |
implicit and explicit parallelism by default, and there is no way |
974 |
for user-space tools to ``opt out''. ML programs that are purely |
|
975 |
functional, output messages only via the official channels |
|
976 |
(\secref{sec:message-channels}), and do not intercept interrupts
|
|
977 |
(\secref{sec:exceptions}) can participate in the multi-threaded
|
|
978 |
environment immediately without further ado. |
|
979 |
||
980 |
More ambitious tools with more fine-grained interaction with the |
|
981 |
environment need to observe the principles explained below. |
|
982 |
*} |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
983 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
984 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
985 |
subsection {* Multi-threading with shared memory *}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
986 |
|
| 39868 | 987 |
text {* Multiple threads help to organize advanced operations of the
|
988 |
system, such as real-time conditions on command transactions, |
|
989 |
sub-components with explicit communication, general asynchronous |
|
990 |
interaction etc. Moreover, parallel evaluation is a prerequisite to |
|
991 |
make adequate use of the CPU resources that are available on |
|
992 |
multi-core systems.\footnote{Multi-core computing does not mean that
|
|
993 |
there are ``spare cycles'' to be wasted. It means that the |
|
994 |
continued exponential speedup of CPU performance due to ``Moore's |
|
995 |
Law'' follows different rules: clock frequency has reached its peak |
|
996 |
around 2005, and applications need to be parallelized in order to |
|
997 |
avoid a perceived loss of performance. See also |
|
998 |
\cite{Sutter:2005}.}
|
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
999 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1000 |
Isabelle/Isar exploits the inherent structure of theories and proofs |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1001 |
to support \emph{implicit parallelism} to a large extent. LCF-style
|
| 39868 | 1002 |
theorem provides almost ideal conditions for that; see also |
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1003 |
\cite{Wenzel:2009}. This means, significant parts of theory and
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1004 |
proof checking is parallelized by default. A maximum speedup-factor |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1005 |
of 3.0 on 4 cores and 5.0 on 8 cores can be |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1006 |
expected.\footnote{Further scalability is limited due to garbage
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1007 |
collection, which is still sequential in Poly/ML 5.2/5.3/5.4. It |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1008 |
helps to provide initial heap space generously, using the |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1009 |
\texttt{-H} option. Initial heap size needs to be scaled-up
|
| 39868 | 1010 |
together with the number of CPU cores: approximately 1--2\,GB per |
1011 |
core..} |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1012 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1013 |
\medskip ML threads lack the memory protection of separate |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1014 |
processes, and operate concurrently on shared heap memory. This has |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1015 |
the advantage that results of independent computations are |
| 39868 | 1016 |
immediately available to other threads: abstract values can be |
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1017 |
passed between threads without copying or awkward serialization that |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1018 |
is typically required for explicit message passing between separate |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1019 |
processes. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1020 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1021 |
To make shared-memory multi-threading work robustly and efficiently, |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1022 |
some programming guidelines need to be observed. While the ML |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1023 |
system is responsible to maintain basic integrity of the |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1024 |
representation of ML values in memory, the application programmer |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1025 |
needs to ensure that multi-threaded execution does not break the |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1026 |
intended semantics. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1027 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1028 |
\begin{warn}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1029 |
To participate in implicit parallelism, tools need to be |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1030 |
thread-safe. A single ill-behaved tool can affect the stability and |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1031 |
performance of the whole system. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1032 |
\end{warn}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1033 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1034 |
Apart from observing the principles of thread-safeness passively, |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1035 |
advanced tools may also exploit parallelism actively, e.g.\ by using |
| 39868 | 1036 |
``future values'' (\secref{sec:futures}) or the more basic library
|
1037 |
functions for parallel list operations (\secref{sec:parlist}).
|
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1038 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1039 |
\begin{warn}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1040 |
Parallel computing resources are managed centrally by the |
| 39868 | 1041 |
Isabelle/ML infrastructure. User programs must not fork their own |
1042 |
ML threads to perform computations. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1043 |
\end{warn}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1044 |
*} |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1045 |
|
| 39868 | 1046 |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1047 |
subsection {* Critical shared resources *}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1048 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1049 |
text {* Thread-safeness is mainly concerned about concurrent
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1050 |
read/write access to shared resources, which are outside the purely |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1051 |
functional world of ML. This covers the following in particular. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1052 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1053 |
\begin{itemize}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1054 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1055 |
\item Global references (or arrays), i.e.\ mutable memory cells that |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1056 |
persist over several invocations of associated |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1057 |
operations.\footnote{This is independent of the visibility of such
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1058 |
mutable values in the toplevel scope.} |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1059 |
|
| 39868 | 1060 |
\item Global state of the running Isabelle/ML process, i.e.\ raw I/O |
1061 |
channels, environment variables, current working directory. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1062 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1063 |
\item Writable resources in the file-system that are shared among |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1064 |
different threads or other processes. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1065 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1066 |
\end{itemize}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1067 |
|
| 39868 | 1068 |
Isabelle/ML provides various mechanisms to avoid critical shared |
1069 |
resources in most practical situations. As last resort there are |
|
1070 |
some mechanisms for explicit synchronization. The following |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1071 |
guidelines help to make Isabelle/ML programs work smoothly in a |
| 39868 | 1072 |
concurrent environment. |
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1073 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1074 |
\begin{itemize}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1075 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1076 |
\item Avoid global references altogether. Isabelle/Isar maintains a |
| 39868 | 1077 |
uniform context that incorporates arbitrary data declared by user |
1078 |
programs (\secref{sec:context-data}). This context is passed as
|
|
1079 |
plain value and user tools can get/map their own data in a purely |
|
1080 |
functional manner. Configuration options within the context |
|
1081 |
(\secref{sec:config-options}) provide simple drop-in replacements
|
|
1082 |
for formerly writable flags. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1083 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1084 |
\item Keep components with local state information re-entrant. |
| 39868 | 1085 |
Instead of poking initial values into (private) global references, a |
1086 |
new state record can be created on each invocation, and passed |
|
1087 |
through any auxiliary functions of the component. The state record |
|
1088 |
may well contain mutable references, without requiring any special |
|
1089 |
synchronizations, as long as each invocation gets its own copy. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1090 |
|
| 39868 | 1091 |
\item Avoid raw output on @{text "stdout"} or @{text "stderr"}. The
|
1092 |
Poly/ML library is thread-safe for each individual output operation, |
|
1093 |
but the ordering of parallel invocations is arbitrary. This means |
|
1094 |
raw output will appear on some system console with unpredictable |
|
1095 |
interleaving of atomic chunks. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1096 |
|
| 39868 | 1097 |
Note that this does not affect regular message output channels |
1098 |
(\secref{sec:message-channels}). An official message is associated
|
|
1099 |
with the command transaction from where it originates, independently |
|
1100 |
of other transactions. This means each running Isar command has |
|
1101 |
effectively its own set of message channels, and interleaving can |
|
1102 |
only happen when commands use parallelism internally (and only at |
|
1103 |
message boundaries). |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1104 |
|
| 39868 | 1105 |
\item Treat environment variables and the current working directory |
1106 |
of the running process as strictly read-only. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1107 |
|
| 39868 | 1108 |
\item Restrict writing to the file-system to unique temporary files. |
1109 |
Isabelle already provides a temporary directory that is unique for |
|
1110 |
the running process, and there is a centralized source of unique |
|
1111 |
serial numbers in Isabelle/ML. Thus temporary files that are passed |
|
1112 |
to to some external process will be always disjoint, and thus |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1113 |
thread-safe. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1114 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1115 |
\end{itemize}
|
| 39868 | 1116 |
*} |
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1117 |
|
| 39868 | 1118 |
text %mlref {*
|
1119 |
\begin{mldecls}
|
|
1120 |
@{index_ML File.tmp_path: "Path.T -> Path.T"} \\
|
|
1121 |
@{index_ML serial_string: "unit -> string"} \\
|
|
1122 |
\end{mldecls}
|
|
1123 |
||
1124 |
\begin{description}
|
|
1125 |
||
1126 |
\item @{ML File.tmp_path}~@{text "path"} relocates the base
|
|
1127 |
component of @{text "path"} into the unique temporary directory of
|
|
1128 |
the running Isabelle/ML process. |
|
1129 |
||
1130 |
\item @{ML serial_string}~@{text "()"} creates a new serial number
|
|
1131 |
that is unique over the runtime of the Isabelle/ML process. |
|
1132 |
||
1133 |
\end{description}
|
|
1134 |
*} |
|
1135 |
||
1136 |
text %mlex {* The following example shows how to create unique
|
|
1137 |
temporary file names. |
|
1138 |
*} |
|
1139 |
||
1140 |
ML {*
|
|
1141 |
val tmp1 = File.tmp_path (Path.basic ("foo" ^ serial_string ()));
|
|
1142 |
val tmp2 = File.tmp_path (Path.basic ("foo" ^ serial_string ()));
|
|
1143 |
@{assert} (tmp1 <> tmp2);
|
|
1144 |
*} |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1145 |
|
| 39868 | 1146 |
|
1147 |
subsection {* Explicit synchronization *}
|
|
1148 |
||
1149 |
text {* Isabelle/ML also provides some explicit synchronization
|
|
1150 |
mechanisms, for the rare situations where mutable shared resources |
|
1151 |
are really required. These are based on the synchronizations |
|
1152 |
primitives of Poly/ML, which have been adapted to the specific |
|
1153 |
assumptions of the concurrent Isabelle/ML environment. User code |
|
1154 |
must not use the Poly/ML primitives directly! |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1155 |
|
| 39868 | 1156 |
\medskip The most basic synchronization concept is a single |
1157 |
\emph{critical section} (also called ``monitor'' in the literature).
|
|
1158 |
A thread that enters the critical section prevents all other threads |
|
1159 |
from doing the same. A thread that is already within the critical |
|
1160 |
section may re-enter it in an idempotent manner. |
|
1161 |
||
1162 |
Such centralized locking is convenient, because it prevents |
|
1163 |
deadlocks by construction. |
|
1164 |
||
1165 |
\medskip More fine-grained locking works via \emph{synchronized
|
|
1166 |
variables}. An explicit state component is associated with |
|
1167 |
mechanisms for locking and signaling. There are operations to |
|
1168 |
await a condition, change the state, and signal the change to all |
|
1169 |
other waiting threads. |
|
1170 |
||
1171 |
Here the synchronized access to the state variable is \emph{not}
|
|
1172 |
re-entrant: direct or indirect nesting within the same thread will |
|
1173 |
cause a deadlock! |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1174 |
*} |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1175 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1176 |
text %mlref {*
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1177 |
\begin{mldecls}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1178 |
@{index_ML NAMED_CRITICAL: "string -> (unit -> 'a) -> 'a"} \\
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1179 |
@{index_ML CRITICAL: "(unit -> 'a) -> 'a"} \\
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1180 |
\end{mldecls}
|
| 39871 | 1181 |
\begin{mldecls}
|
1182 |
@{index_ML_type "'a Synchronized.var"} \\
|
|
1183 |
@{index_ML Synchronized.var: "string -> 'a -> 'a Synchronized.var"} \\
|
|
1184 |
@{index_ML Synchronized.guarded_access: "'a Synchronized.var ->
|
|
1185 |
('a -> ('b * 'a) option) -> 'b"} \\
|
|
1186 |
\end{mldecls}
|
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1187 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1188 |
\begin{description}
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1189 |
|
| 39868 | 1190 |
\item @{ML NAMED_CRITICAL}~@{text "name e"} evaluates @{text "e ()"}
|
1191 |
within the central critical section of Isabelle/ML. No other thread |
|
1192 |
may do so at the same time, but non-critical parallel execution will |
|
| 39871 | 1193 |
continue. The @{text "name"} argument is used for tracing and might
|
| 39868 | 1194 |
help to spot sources of congestion. |
1195 |
||
1196 |
Entering the critical section without contention is very fast, and |
|
1197 |
several basic system operations do so frequently. Each thread |
|
1198 |
should leave the critical section quickly, otherwise parallel |
|
1199 |
performance may degrade. |
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1200 |
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1201 |
\item @{ML CRITICAL} is the same as @{ML NAMED_CRITICAL} with empty
|
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1202 |
name argument. |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1203 |
|
| 39871 | 1204 |
\item Type @{ML_type "'a Synchronized.var"} represents synchronized
|
1205 |
variables with state of type @{ML_type 'a}.
|
|
1206 |
||
1207 |
\item @{ML Synchronized.var}~@{text "name x"} creates a synchronized
|
|
1208 |
variable that is initialized with value @{text "x"}. The @{text
|
|
1209 |
"name"} is used for tracing. |
|
1210 |
||
1211 |
\item @{ML Synchronized.guarded_access}~@{text "var f"} lets the
|
|
1212 |
function @{text "f"} operate within a critical section on the state
|
|
1213 |
@{text "x"} as follows: if @{text "f x"} produces @{ML NONE}, we
|
|
1214 |
continue to wait on the internal condition variable, expecting that |
|
1215 |
some other thread will eventually change the content in a suitable |
|
1216 |
manner; if @{text "f x"} produces @{ML SOME}~@{text "(y, x')"} we
|
|
1217 |
are satisfied and assign the new state value @{text "x'"}, broadcast
|
|
1218 |
a signal to all waiting threads on the associated condition |
|
1219 |
variable, and return the result @{text "y"}.
|
|
1220 |
||
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1221 |
\end{description}
|
| 39871 | 1222 |
|
1223 |
There are some further variants of the general @{ML
|
|
1224 |
Synchronized.guarded_access} combinator, see @{"file"
|
|
1225 |
"~~/src/Pure/Concurrent/synchronized.ML"} for details. |
|
1226 |
*} |
|
1227 |
||
1228 |
text %mlex {* See @{"file" "~~/src/Pure/Concurrent/mailbox.ML"} how to
|
|
1229 |
implement a mailbox as synchronized variable over a purely |
|
1230 |
functional queue. |
|
1231 |
||
1232 |
\medskip The following example implements a counter that produces |
|
1233 |
positive integers that are unique over the runtime of the Isabelle |
|
1234 |
process: |
|
1235 |
*} |
|
1236 |
||
1237 |
ML {*
|
|
1238 |
local |
|
1239 |
val counter = Synchronized.var "counter" 0; |
|
1240 |
in |
|
1241 |
fun next () = |
|
1242 |
Synchronized.guarded_access counter |
|
1243 |
(fn i => |
|
1244 |
let val j = i + 1 |
|
1245 |
in SOME (j, j) end); |
|
1246 |
end; |
|
1247 |
*} |
|
1248 |
||
1249 |
ML {*
|
|
1250 |
val a = next (); |
|
1251 |
val b = next (); |
|
1252 |
@{assert} (a <> b);
|
|
|
39867
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1253 |
*} |
|
a8363532cd4d
somewhat modernized version of "Thread-safe programming";
wenzelm
parents:
39866
diff
changeset
|
1254 |
|
|
30270
61811c9224a6
dummy changes to produce a new changeset of these files;
wenzelm
parents:
29755
diff
changeset
|
1255 |
end |