src/HOL/SPARK/Manual/Reference.thy
author wenzelm
Sat Nov 04 15:24:40 2017 +0100 (21 months ago)
changeset 67003 49850a679c2c
parent 66992 69673025292e
child 69597 ff784d5a5bfb
permissions -rw-r--r--
more robust sorted_entries;
berghofe@45044
     1
(*<*)
berghofe@45044
     2
theory Reference
wenzelm@66992
     3
imports "HOL-SPARK.SPARK"
berghofe@45044
     4
begin
berghofe@45044
     5
berghofe@45044
     6
syntax (my_constrain output)
wenzelm@61143
     7
  "_constrain" :: "logic => type => logic" ("_ :: _" [4, 0] 3)
berghofe@45044
     8
(*>*)
berghofe@45044
     9
wenzelm@63167
    10
chapter \<open>HOL-\SPARK{} Reference\<close>
berghofe@45044
    11
wenzelm@63167
    12
text \<open>
berghofe@45044
    13
\label{sec:spark-reference}
berghofe@45044
    14
This section is intended as a quick reference for the HOL-\SPARK{} verification
berghofe@45044
    15
environment. In \secref{sec:spark-commands}, we give a summary of the commands
berghofe@45044
    16
provided by the HOL-\SPARK{}, while \secref{sec:spark-types} contains a description
berghofe@45044
    17
of how particular types of \SPARK{} and FDL are modelled in Isabelle.
wenzelm@63167
    18
\<close>
berghofe@45044
    19
wenzelm@63167
    20
section \<open>Commands\<close>
berghofe@45044
    21
wenzelm@63167
    22
text \<open>
berghofe@45044
    23
\label{sec:spark-commands}
berghofe@45044
    24
This section describes the syntax and effect of each of the commands provided
berghofe@45044
    25
by HOL-\SPARK{}.
wenzelm@59938
    26
@{rail \<open>
wenzelm@59938
    27
  @'spark_open' name ('(' name ')')?
wenzelm@59938
    28
\<close>}
berghofe@56798
    29
Opens a new \SPARK{} verification environment and loads a \texttt{*.siv} file with VCs.
berghofe@56798
    30
Alternatively, \texttt{*.vcg} files can be loaded using \isa{\isacommand{spark\_open\_vcg}}.
berghofe@56798
    31
The corresponding \texttt{*.fdl} and \texttt{*.rls}
berghofe@45044
    32
files must reside in the same directory as the file given as an argument to the command.
berghofe@45044
    33
This command also generates records and datatypes for the types specified in the
berghofe@45044
    34
\texttt{*.fdl} file, unless they have already been associated with user-defined
berghofe@45044
    35
Isabelle types (see below).
berghofe@45044
    36
Since the full package name currently cannot be determined from the files generated by the
berghofe@45044
    37
\SPARK{} Examiner, the command also allows to specify an optional package prefix in the
berghofe@45044
    38
format \texttt{$p_1$\_\_$\ldots$\_\_$p_n$}. When working with projects consisting of several
berghofe@45044
    39
packages, this is necessary in order for the verification environment to be able to map proof
berghofe@45044
    40
functions and types defined in Isabelle to their \SPARK{} counterparts.
wenzelm@59938
    41
@{rail \<open>
wenzelm@59938
    42
  @'spark_proof_functions' ((name '=' term)+)
wenzelm@59938
    43
\<close>}
berghofe@45044
    44
Associates a proof function with the given name to a term. The name should be the full name
berghofe@45044
    45
of the proof function as it appears in the \texttt{*.fdl} file, including the package prefix.
berghofe@45044
    46
This command can be used both inside and outside a verification environment. The latter
berghofe@45044
    47
variant is useful for introducing proof functions that are shared by several procedures
berghofe@45044
    48
or packages, whereas the former allows the given term to refer to the types generated
berghofe@45044
    49
by \isa{\isacommand{spark\_open}} for record or enumeration types specified in the
berghofe@45044
    50
\texttt{*.fdl} file.
wenzelm@59938
    51
@{rail \<open>
wenzelm@59938
    52
  @'spark_types' ((name '=' type (mapping?))+)
wenzelm@59938
    53
  ;
wenzelm@62969
    54
  mapping: '('((name '=' name)+',')')'
wenzelm@59938
    55
\<close>}
berghofe@45044
    56
Associates a \SPARK{} type with the given name with an Isabelle type. This command can
berghofe@45044
    57
only be used outside a verification environment. The given type must be either a record
berghofe@46725
    58
or a datatype, where the names of fields or constructors must either match those of the
berghofe@46725
    59
corresponding \SPARK{} types (modulo casing), or a mapping from \SPARK{} to Isabelle
berghofe@46725
    60
names has to be provided.
berghofe@46725
    61
This command is useful when having to define
berghofe@45044
    62
proof functions referring to record or enumeration types that are shared by several
berghofe@45044
    63
procedures or packages. First, the types required by the proof functions can be introduced
berghofe@45044
    64
using Isabelle's commands for defining records or datatypes. Having introduced the
berghofe@45044
    65
types, the proof functions can be defined in Isabelle. Finally, both the proof
berghofe@45044
    66
functions and the types can be associated with their \SPARK{} counterparts.
wenzelm@59938
    67
@{rail \<open>
wenzelm@59938
    68
  @'spark_status' (('(proved)' | '(unproved)')?)
wenzelm@59938
    69
\<close>}
berghofe@45044
    70
Outputs the variables declared in the \texttt{*.fdl} file, the rules declared in
berghofe@45044
    71
the \texttt{*.rls} file, and all VCs, together with their status (proved, unproved).
berghofe@45044
    72
The output can be restricted to the proved or unproved VCs by giving the corresponding
berghofe@45044
    73
option to the command.
wenzelm@59938
    74
@{rail \<open>
wenzelm@59938
    75
  @'spark_vc' name
wenzelm@59938
    76
\<close>}
berghofe@45044
    77
Initiates the proof of the VC with the given name. Similar to the standard
berghofe@45044
    78
\isa{\isacommand{lemma}} or \isa{\isacommand{theorem}} commands, this command
berghofe@45044
    79
must be followed by a sequence of proof commands. The command introduces the
berghofe@45044
    80
hypotheses \texttt{H1} \dots \texttt{H$n$}, as well as the identifiers
berghofe@45044
    81
\texttt{?C1} \dots \texttt{?C$m$} corresponding to the conclusions of the VC.
wenzelm@59938
    82
@{rail \<open>
wenzelm@59938
    83
  @'spark_end' '(incomplete)'?
wenzelm@59938
    84
\<close>}
berghofe@48168
    85
Closes the current verification environment. Unless the \texttt{incomplete}
berghofe@48168
    86
option is given, all VCs must have been proved,
berghofe@45044
    87
otherwise the command issues an error message. As a side effect, the command
berghofe@45044
    88
generates a proof review (\texttt{*.prv}) file to inform POGS of the proved
berghofe@45044
    89
VCs.
wenzelm@63167
    90
\<close>
berghofe@45044
    91
wenzelm@63167
    92
section \<open>Types\<close>
berghofe@45044
    93
wenzelm@63167
    94
text \<open>
berghofe@45044
    95
\label{sec:spark-types}
berghofe@45044
    96
The main types of FDL are integers, enumeration types, records, and arrays.
berghofe@45044
    97
In the following sections, we describe how these types are modelled in
berghofe@45044
    98
Isabelle.
wenzelm@63167
    99
\<close>
berghofe@45044
   100
wenzelm@63167
   101
subsection \<open>Integers\<close>
berghofe@45044
   102
wenzelm@63167
   103
text \<open>
berghofe@45044
   104
The FDL type \texttt{integer} is modelled by the Isabelle type @{typ int}.
berghofe@45044
   105
While the FDL \texttt{mod} operator behaves in the same way as its Isabelle
berghofe@45044
   106
counterpart, this is not the case for the \texttt{div} operator. As has already
berghofe@45044
   107
been mentioned in \secref{sec:proving-vcs}, the \texttt{div} operator of \SPARK{}
wenzelm@63167
   108
always truncates towards zero, whereas the \<open>div\<close> operator of Isabelle
berghofe@45044
   109
truncates towards minus infinity. Therefore, the FDL \texttt{div} operator is
wenzelm@63167
   110
mapped to the \<open>sdiv\<close> operator in Isabelle. The characteristic theorems
wenzelm@63167
   111
of \<open>sdiv\<close>, in particular those describing the relationship with the standard
wenzelm@63167
   112
\<open>div\<close> operator, are shown in \figref{fig:sdiv-properties}
berghofe@45044
   113
\begin{figure}
berghofe@45044
   114
\begin{center}
berghofe@45044
   115
\small
berghofe@45044
   116
\begin{tabular}{ll}
wenzelm@63167
   117
\<open>sdiv_def\<close>: & @{thm sdiv_def} \\
wenzelm@63167
   118
\<open>sdiv_minus_dividend\<close>: & @{thm sdiv_minus_dividend} \\
wenzelm@63167
   119
\<open>sdiv_minus_divisor\<close>: & @{thm sdiv_minus_divisor} \\
wenzelm@63167
   120
\<open>sdiv_pos_pos\<close>: & @{thm [mode=no_brackets] sdiv_pos_pos} \\
wenzelm@63167
   121
\<open>sdiv_pos_neg\<close>: & @{thm [mode=no_brackets] sdiv_pos_neg} \\
wenzelm@63167
   122
\<open>sdiv_neg_pos\<close>: & @{thm [mode=no_brackets] sdiv_neg_pos} \\
wenzelm@63167
   123
\<open>sdiv_neg_neg\<close>: & @{thm [mode=no_brackets] sdiv_neg_neg} \\
berghofe@45044
   124
\end{tabular}
berghofe@45044
   125
\end{center}
wenzelm@63167
   126
\caption{Characteristic properties of \<open>sdiv\<close>}
berghofe@45044
   127
\label{fig:sdiv-properties}
berghofe@45044
   128
\end{figure}
berghofe@45044
   129
berghofe@45044
   130
\begin{figure}
berghofe@45044
   131
\begin{center}
berghofe@45044
   132
\small
berghofe@45044
   133
\begin{tabular}{ll}
wenzelm@63167
   134
\<open>AND_lower\<close>: & @{thm [mode=no_brackets] AND_lower} \\
wenzelm@63167
   135
\<open>OR_lower\<close>: & @{thm [mode=no_brackets] OR_lower} \\
wenzelm@63167
   136
\<open>XOR_lower\<close>: & @{thm [mode=no_brackets] XOR_lower} \\
wenzelm@63167
   137
\<open>AND_upper1\<close>: & @{thm [mode=no_brackets] AND_upper1} \\
wenzelm@63167
   138
\<open>AND_upper2\<close>: & @{thm [mode=no_brackets] AND_upper2} \\
wenzelm@63167
   139
\<open>OR_upper\<close>: & @{thm [mode=no_brackets] OR_upper} \\
wenzelm@63167
   140
\<open>XOR_upper\<close>: & @{thm [mode=no_brackets] XOR_upper} \\
wenzelm@63167
   141
\<open>AND_mod\<close>: & @{thm [mode=no_brackets] AND_mod}
berghofe@45044
   142
\end{tabular}
berghofe@45044
   143
\end{center}
berghofe@45044
   144
\caption{Characteristic properties of bitwise operators}
berghofe@45044
   145
\label{fig:bitwise}
berghofe@45044
   146
\end{figure}
berghofe@45044
   147
The bitwise logical operators of \SPARK{} and FDL are modelled by the operators
wenzelm@63167
   148
\<open>AND\<close>, \<open>OR\<close> and \<open>XOR\<close> from Isabelle's \<open>Word\<close> library,
berghofe@45044
   149
all of which have type @{typ "int \<Rightarrow> int \<Rightarrow> int"}. A list of properties of these
berghofe@45044
   150
operators that are useful in proofs about \SPARK{} programs are shown in
berghofe@45044
   151
\figref{fig:bitwise}
wenzelm@63167
   152
\<close>
berghofe@45044
   153
wenzelm@63167
   154
subsection \<open>Enumeration types\<close>
berghofe@45044
   155
wenzelm@63167
   156
text \<open>
berghofe@45044
   157
The FDL enumeration type
berghofe@45044
   158
\begin{alltt}
berghofe@45044
   159
type \(t\) = (\(e\sb{1}\), \(e\sb{2}\), \dots, \(e\sb{n}\));
berghofe@45044
   160
\end{alltt}
berghofe@45044
   161
is modelled by the Isabelle datatype
berghofe@45044
   162
\begin{isabelle}
berghofe@45044
   163
\normalsize
berghofe@45044
   164
\isacommand{datatype}\ $t$\ =\ $e_1$\ $\mid$\ $e_2$\ $\mid$\ \dots\ $\mid$\ $e_n$
berghofe@45044
   165
\end{isabelle}
berghofe@45044
   166
The HOL-\SPARK{} environment defines a type class @{class spark_enum} that captures
berghofe@45044
   167
the characteristic properties of all enumeration types. It provides the following
wenzelm@63167
   168
polymorphic functions and constants for all types \<open>'a\<close> of this type class:
berghofe@45044
   169
\begin{flushleft}
berghofe@45044
   170
@{term_type [mode=my_constrain] pos} \\
berghofe@45044
   171
@{term_type [mode=my_constrain] val} \\
berghofe@45044
   172
@{term_type [mode=my_constrain] succ} \\
berghofe@45044
   173
@{term_type [mode=my_constrain] pred} \\
berghofe@45044
   174
@{term_type [mode=my_constrain] first_el} \\
berghofe@45044
   175
@{term_type [mode=my_constrain] last_el}
berghofe@45044
   176
\end{flushleft}
berghofe@45044
   177
In addition, @{class spark_enum} is a subclass of the @{class linorder} type class,
wenzelm@63167
   178
which allows the comparison operators \<open><\<close> and \<open>\<le>\<close> to be used on
berghofe@45044
   179
enumeration types. The polymorphic operations shown above enjoy a number of
berghofe@45044
   180
generic properties that hold for all enumeration types. These properties are
berghofe@45044
   181
listed in \figref{fig:enum-generic-properties}.
berghofe@45044
   182
Moreover, \figref{fig:enum-specific-properties} shows a list of properties
berghofe@45044
   183
that are specific to each enumeration type $t$, such as the characteristic
berghofe@45044
   184
equations for @{term val} and @{term pos}.
berghofe@45044
   185
\begin{figure}[t]
berghofe@45044
   186
\begin{center}
berghofe@45044
   187
\small
berghofe@45044
   188
\begin{tabular}{ll}
wenzelm@63167
   189
\<open>range_pos\<close>: & @{thm range_pos} \\
wenzelm@63167
   190
\<open>less_pos\<close>: & @{thm less_pos} \\
wenzelm@63167
   191
\<open>less_eq_pos\<close>: & @{thm less_eq_pos} \\
wenzelm@63167
   192
\<open>val_def\<close>: & @{thm val_def} \\
wenzelm@63167
   193
\<open>succ_def\<close>: & @{thm succ_def} \\
wenzelm@63167
   194
\<open>pred_def\<close>: & @{thm pred_def} \\
wenzelm@63167
   195
\<open>first_el_def\<close>: & @{thm first_el_def} \\
wenzelm@63167
   196
\<open>last_el_def\<close>: & @{thm last_el_def} \\
wenzelm@63167
   197
\<open>inj_pos\<close>: & @{thm inj_pos} \\
wenzelm@63167
   198
\<open>val_pos\<close>: & @{thm val_pos} \\
wenzelm@63167
   199
\<open>pos_val\<close>: & @{thm pos_val} \\
wenzelm@63167
   200
\<open>first_el_smallest\<close>: & @{thm first_el_smallest} \\
wenzelm@63167
   201
\<open>last_el_greatest\<close>: & @{thm last_el_greatest} \\
wenzelm@63167
   202
\<open>pos_succ\<close>: & @{thm pos_succ} \\
wenzelm@63167
   203
\<open>pos_pred\<close>: & @{thm pos_pred} \\
wenzelm@63167
   204
\<open>succ_val\<close>: & @{thm succ_val} \\
wenzelm@63167
   205
\<open>pred_val\<close>: & @{thm pred_val}
berghofe@45044
   206
\end{tabular}
berghofe@45044
   207
\end{center}
berghofe@45044
   208
\caption{Generic properties of functions on enumeration types}
berghofe@45044
   209
\label{fig:enum-generic-properties}
berghofe@45044
   210
\end{figure}
berghofe@45044
   211
\begin{figure}[t]
berghofe@45044
   212
\begin{center}
berghofe@45044
   213
\small
berghofe@45044
   214
\begin{tabular}{ll@ {\hspace{2cm}}ll}
berghofe@45044
   215
\texttt{$t$\_val}: & \isa{val\ $0$\ =\ $e_1$} & \texttt{$t$\_pos}: & pos\ $e_1$\ =\ $0$ \\
berghofe@45044
   216
                   & \isa{val\ $1$\ =\ $e_2$} &                    & pos\ $e_2$\ =\ $1$ \\
berghofe@45044
   217
                   & \hspace{1cm}\vdots       &                    & \hspace{1cm}\vdots \\
berghofe@45044
   218
                   & \isa{val\ $(n-1)$\ =\ $e_n$} &                & pos\ $e_n$\ =\ $n-1$
berghofe@45044
   219
\end{tabular} \\[3ex]
berghofe@45044
   220
\begin{tabular}{ll}
berghofe@45044
   221
\texttt{$t$\_card}: & \isa{card($t$)\ =\ $n$} \\
berghofe@45044
   222
\texttt{$t$\_first\_el}: & \isa{first\_el\ =\ $e_1$} \\
berghofe@45044
   223
\texttt{$t$\_last\_el}: & \isa{last\_el\ =\ $e_n$}
berghofe@45044
   224
\end{tabular}
berghofe@45044
   225
\end{center}
berghofe@45044
   226
\caption{Type-specific properties of functions on enumeration types}
berghofe@45044
   227
\label{fig:enum-specific-properties}
berghofe@45044
   228
\end{figure}
wenzelm@63167
   229
\<close>
berghofe@45044
   230
wenzelm@63167
   231
subsection \<open>Records\<close>
berghofe@45044
   232
wenzelm@63167
   233
text \<open>
berghofe@45044
   234
The FDL record type
berghofe@45044
   235
\begin{alltt}
berghofe@45044
   236
type \(t\) = record
berghofe@45044
   237
      \(f\sb{1}\) : \(t\sb{1}\);
berghofe@45044
   238
       \(\vdots\)
berghofe@45044
   239
      \(f\sb{n}\) : \(t\sb{n}\)
berghofe@45044
   240
   end;
berghofe@45044
   241
\end{alltt}
berghofe@45044
   242
is modelled by the Isabelle record type
berghofe@45044
   243
\begin{isabelle}
berghofe@45044
   244
\normalsize
berghofe@45044
   245
\isacommand{record}\ t\ = \isanewline
berghofe@45044
   246
\ \ $f_1$\ ::\ $t_1$ \isanewline
berghofe@45044
   247
\ \ \ \vdots \isanewline
berghofe@45044
   248
\ \ $f_n$\ ::\ $t_n$
berghofe@45044
   249
\end{isabelle}
berghofe@45044
   250
Records are constructed using the notation
berghofe@45044
   251
\isa{\isasymlparr$f_1$\ =\ $v_1$,\ $\ldots$,\ $f_n$\ =\ $v_n$\isasymrparr},
berghofe@45044
   252
a field $f_i$ of a record $r$ is selected using the notation $f_i~r$, and the
berghofe@45044
   253
fields $f$ and $f'$ of a record $r$ can be updated using the notation
berghofe@45044
   254
\mbox{\isa{$r$\ \isasymlparr$f$\ :=\ $v$,\ $f'$\ :=\ $v'$\isasymrparr}}.
wenzelm@63167
   255
\<close>
berghofe@45044
   256
wenzelm@63167
   257
subsection \<open>Arrays\<close>
berghofe@45044
   258
wenzelm@63167
   259
text \<open>
berghofe@45044
   260
The FDL array type
berghofe@45044
   261
\begin{alltt}
berghofe@45044
   262
type \(t\) = array [\(t\sb{1}\), \(\ldots\), \(t\sb{n}\)] of \(u\);
berghofe@45044
   263
\end{alltt}
berghofe@45044
   264
is modelled by the Isabelle function type $t_1 \times \cdots \times t_n \Rightarrow u$.
berghofe@45044
   265
Array updates are written as \isa{$A$($x_1$\ := $y_1$,\ \dots,\ $x_n$\ :=\ $y_n$)}.
berghofe@45044
   266
To allow updating an array at a set of indices, HOL-\SPARK{} provides the notation
berghofe@45044
   267
\isa{\dots\ [:=]\ \dots}, which can be combined with \isa{\dots\ :=\ \dots} and has
berghofe@45044
   268
the properties
berghofe@45044
   269
@{thm [display,mode=no_brackets] fun_upds_in fun_upds_notin upds_singleton}
berghofe@45044
   270
Thus, we can write expressions like
berghofe@45044
   271
@{term [display] "(A::int\<Rightarrow>int) ({0..9} [:=] 42, 15 := 99, {20..29} [:=] 0)"}
berghofe@45044
   272
that would be cumbersome to write using single updates.
wenzelm@63167
   273
\<close>
berghofe@45044
   274
wenzelm@63167
   275
section \<open>User-defined proof functions and types\<close>
berghofe@45044
   276
wenzelm@63167
   277
text \<open>
berghofe@45044
   278
To illustrate the interplay between the commands for introducing user-defined proof
berghofe@45044
   279
functions and types mentioned in \secref{sec:spark-commands}, we now discuss a larger
berghofe@45044
   280
example involving the definition of proof functions on complex types. Assume we would
berghofe@45044
   281
like to define an array type, whose elements are records that themselves contain
berghofe@45044
   282
arrays. Moreover, assume we would like to initialize all array elements and record
berghofe@45044
   283
fields of type \texttt{Integer} in an array of this type with the value \texttt{0}.
berghofe@45044
   284
The specification of package \texttt{Complex\_Types} containing the definition of
berghofe@45044
   285
the array type, which we call \texttt{Array\_Type2}, is shown in \figref{fig:complex-types}.
berghofe@45044
   286
It also contains the declaration of a proof function \texttt{Initialized} that is used
berghofe@45044
   287
to express that the array has been initialized. The two other proof functions
berghofe@45044
   288
\texttt{Initialized2} and \texttt{Initialized3} are used to reason about the
berghofe@45044
   289
initialization of the inner array. Since the array types and proof functions
berghofe@45044
   290
may be used by several packages, such as the one shown in \figref{fig:complex-types-app},
berghofe@45044
   291
it is advantageous to define the proof functions in a central theory that can
berghofe@45044
   292
be included by other theories containing proofs about packages using \texttt{Complex\_Types}.
berghofe@45044
   293
We show this theory in \figref{fig:complex-types-thy}. Since the proof functions
berghofe@45044
   294
refer to the enumeration and record types defined in \texttt{Complex\_Types},
berghofe@45044
   295
we need to define the Isabelle counterparts of these types using the
berghofe@45044
   296
\isa{\isacommand{datatype}} and \isa{\isacommand{record}} commands in order
berghofe@45044
   297
to be able to write down the definition of the proof functions. These types are
berghofe@45044
   298
linked to the corresponding \SPARK{} types using the \isa{\isacommand{spark\_types}}
berghofe@45044
   299
command. Note that we have to specify the full name of the \SPARK{} functions
berghofe@45044
   300
including the package prefix. Using the logic of Isabelle, we can then define
berghofe@45044
   301
functions involving the enumeration and record types introduced above, and link
berghofe@45044
   302
them to the corresponding \SPARK{} proof functions. It is important that the
berghofe@45044
   303
\isa{\isacommand{definition}} commands are preceeded by the \isa{\isacommand{spark\_types}}
wenzelm@63167
   304
command, since the definition of \<open>initialized3\<close> uses the \<open>val\<close>
wenzelm@63167
   305
function for enumeration types that is only available once that \<open>day\<close>
berghofe@45044
   306
has been declared as a \SPARK{} type.
berghofe@45044
   307
\begin{figure}
berghofe@45044
   308
\lstinputlisting{complex_types.ads}
berghofe@45044
   309
\caption{Nested array and record types}
berghofe@45044
   310
\label{fig:complex-types}
berghofe@45044
   311
\end{figure}
berghofe@45044
   312
\begin{figure}
berghofe@45044
   313
\lstinputlisting{complex_types_app.ads}
berghofe@45044
   314
\lstinputlisting{complex_types_app.adb}
berghofe@45044
   315
\caption{Application of \texttt{Complex\_Types} package}
berghofe@45044
   316
\label{fig:complex-types-app}
berghofe@45044
   317
\end{figure}
berghofe@45044
   318
\begin{figure}
berghofe@45044
   319
\input{Complex_Types}
berghofe@45044
   320
\caption{Theory defining proof functions for complex types}
berghofe@45044
   321
\label{fig:complex-types-thy}
berghofe@45044
   322
\end{figure}
wenzelm@63167
   323
\<close>
berghofe@45044
   324
berghofe@45044
   325
(*<*)
berghofe@45044
   326
end
berghofe@45044
   327
(*>*)