32
+ − 1
theory Ind_Interface
42
+ − 2
imports "../Base" Simple_Inductive_Package
32
+ − 3
begin
+ − 4
88
+ − 5
section{* The Interface \label{sec:ind-interface} *}
32
+ − 6
+ − 7
text {*
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 8
88
+ − 9
In order to add a new inductive predicate to a theory with the help of our
+ − 10
package, the user must \emph{invoke} it. For every package, there are
+ − 11
essentially two different ways of invoking it, which we will refer to as
+ − 12
\emph{external} and \emph{internal}. By external invocation we mean that the
+ − 13
package is called from within a theory document. In this case, the type of
+ − 14
the inductive predicate, as well as its introduction rules, are given as
+ − 15
strings by the user. Before the package can actually make the definition,
+ − 16
the type and introduction rules have to be parsed. In contrast, internal
+ − 17
invocation means that the package is called by some other package. For
+ − 18
example, the function definition package \cite{Krauss-IJCAR06} calls the
+ − 19
inductive definition package to define the graph of the function. However,
+ − 20
it is not a good idea for the function definition package to pass the
+ − 21
introduction rules for the function graph to the inductive definition
+ − 22
package as strings. In this case, it is better to directly pass the rules to
+ − 23
the package as a list of terms, which is more robust than handling strings
+ − 24
that are lacking the additional structure of terms. These two ways of
+ − 25
invoking the package are reflected in its ML programming interface, which
+ − 26
consists of two functions:
+ − 27
+ − 28
@{ML_chunk [display] SIMPLE_INDUCTIVE_PACKAGE}
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 29
*}
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 30
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 31
text {*
88
+ − 32
The function for external invocation of the package is called @{ML
+ − 33
add_inductive in SimpleInductivePackage}, whereas the one for internal
+ − 34
invocation is called @{ML add_inductive_i in SimpleInductivePackage}. Both
+ − 35
of these functions take as arguments the names and types of the inductive
+ − 36
predicates, the names and types of their parameters, the actual introduction
+ − 37
rules and a \emph{local theory}. They return a local theory containing the
+ − 38
definition, together with a tuple containing the introduction and induction
+ − 39
rules, which are stored in the local theory, too. In contrast to an
+ − 40
ordinary theory, which simply consists of a type signature, as well as
+ − 41
tables for constants, axioms and theorems, a local theory also contains
+ − 42
additional context information, such as locally fixed variables and local
+ − 43
assumptions that may be used by the package. The type @{ML_type
+ − 44
local_theory} is identical to the type of \emph{proof contexts} @{ML_type
+ − 45
"Proof.context"}, although not every proof context constitutes a valid local
+ − 46
theory. Note that @{ML add_inductive_i in SimpleInductivePackage} expects
+ − 47
the types of the predicates and parameters to be specified using the
+ − 48
datatype @{ML_type typ} of Isabelle's logical framework, whereas @{ML
+ − 49
add_inductive in SimpleInductivePackage} expects them to be given as
+ − 50
optional strings. If no string is given for a particular predicate or
+ − 51
parameter, this means that the type should be inferred by the
+ − 52
package. Additional \emph{mixfix syntax} may be associated with the
+ − 53
predicates and parameters as well. Note that @{ML add_inductive_i in
+ − 54
SimpleInductivePackage} does not allow mixfix syntax to be associated with
+ − 55
parameters, since it can only be used for parsing. The names of the
+ − 56
predicates, parameters and rules are represented by the type @{ML_type
+ − 57
Binding.binding}. Strings can be turned into elements of the type @{ML_type
+ − 58
Binding.binding} using the function @{ML [display] "Binding.name : string ->
+ − 59
Binding.binding"} Each introduction rule is given as a tuple containing its
+ − 60
name, a list of \emph{attributes} and a logical formula. Note that the type
+ − 61
@{ML_type Attrib.binding} used in the list of introduction rules is just a
+ − 62
shorthand for the type @{ML_type "Binding.binding * Attrib.src list"}. The
+ − 63
function @{ML add_inductive_i in SimpleInductivePackage} expects the formula
+ − 64
to be specified using the datatype @{ML_type term}, whereas @{ML
+ − 65
add_inductive in SimpleInductivePackage} expects it to be given as a string.
+ − 66
An attribute specifies additional actions and transformations that should be
+ − 67
applied to a theorem, such as storing it in the rule databases used by
+ − 68
automatic tactics like the simplifier. The code of the package, which will
+ − 69
be described in the following section, will mostly treat attributes as a
+ − 70
black box and just forward them to other functions for storing theorems in
+ − 71
local theories. The implementation of the function @{ML add_inductive in
+ − 72
SimpleInductivePackage} for external invocation of the package is quite
+ − 73
simple. Essentially, it just parses the introduction rules and then passes
+ − 74
them on to @{ML add_inductive_i in SimpleInductivePackage}:
+ − 75
+ − 76
@{ML_chunk [display] add_inductive}
+ − 77
+ − 78
For parsing and type checking the introduction rules, we use the function
+ − 79
+ − 80
@{ML [display] "Specification.read_specification:
76
+ − 81
(Binding.binding * string option * mixfix) list -> (*{variables}*)
32
+ − 82
(Attrib.binding * string list) list list -> (*{rules}*)
+ − 83
local_theory ->
76
+ − 84
(((Binding.binding * typ) * mixfix) list *
32
+ − 85
(Attrib.binding * term list) list) *
+ − 86
local_theory"}
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 87
*}
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 88
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 89
text {*
88
+ − 90
During parsing, both predicates and parameters are treated as variables, so
+ − 91
the lists \verb!preds_syn! and \verb!params_syn! are just appended
+ − 92
before being passed to @{ML read_specification in Specification}. Note that the format
+ − 93
for rules supported by @{ML read_specification in Specification} is more general than
+ − 94
what is required for our package. It allows several rules to be associated
+ − 95
with one name, and the list of rules can be partitioned into several
+ − 96
sublists. In order for the list \verb!intro_srcs! of introduction rules
+ − 97
to be acceptable as an input for @{ML read_specification in Specification}, we first
+ − 98
have to turn it into a list of singleton lists. This transformation
+ − 99
has to be reversed later on by applying the function
+ − 100
@{ML [display] "the_single: 'a list -> 'a"}
+ − 101
to the list \verb!specs! containing the parsed introduction rules.
+ − 102
The function @{ML read_specification in Specification} also returns the list \verb!vars!
+ − 103
of predicates and parameters that contains the inferred types as well.
+ − 104
This list has to be chopped into the two lists \verb!preds_syn'! and
+ − 105
\verb!params_syn'! for predicates and parameters, respectively.
+ − 106
All variables occurring in a rule but not in the list of variables passed to
+ − 107
@{ML read_specification in Specification} will be bound by a meta-level universal
+ − 108
quantifier.
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 109
*}
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 110
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 111
text {*
88
+ − 112
Finally, @{ML read_specification in Specification} also returns another local theory,
+ − 113
but we can safely discard it. As an example, let us look at how we can use this
+ − 114
function to parse the introduction rules of the @{text trcl} predicate:
+ − 115
+ − 116
@{ML_response [display]
32
+ − 117
"Specification.read_specification
55
+ − 118
[(Binding.name \"trcl\", NONE, NoSyn),
+ − 119
(Binding.name \"r\", SOME \"'a \<Rightarrow> 'a \<Rightarrow> bool\", NoSyn)]
+ − 120
[[((Binding.name \"base\", []), [\"trcl r x x\"])],
+ − 121
[((Binding.name \"step\", []), [\"trcl r x y \<Longrightarrow> r y z \<Longrightarrow> trcl r x z\"])]]
32
+ − 122
@{context}"
+ − 123
"((\<dots>,
+ − 124
[(\<dots>,
+ − 125
[Const (\"all\", \<dots>) $ Abs (\"x\", TFree (\"'a\", \<dots>),
+ − 126
Const (\"Trueprop\", \<dots>) $
+ − 127
(Free (\"trcl\", \<dots>) $ Free (\"r\", \<dots>) $ Bound 0 $ Bound 0))]),
+ − 128
(\<dots>,
+ − 129
[Const (\"all\", \<dots>) $ Abs (\"x\", TFree (\"'a\", \<dots>),
+ − 130
Const (\"all\", \<dots>) $ Abs (\"y\", TFree (\"'a\", \<dots>),
+ − 131
Const (\"all\", \<dots>) $ Abs (\"z\", TFree (\"'a\", \<dots>),
+ − 132
Const (\"==>\", \<dots>) $
+ − 133
(Const (\"Trueprop\", \<dots>) $
42
+ − 134
(Free (\"trcl\", \<dots>) $ Free (\"r\", \<dots>) $ Bound 2 $ Bound 1)) $
32
+ − 135
(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>))))])]),
+ − 136
\<dots>)
76
+ − 137
: (((Binding.binding * typ) * mixfix) list *
32
+ − 138
(Attrib.binding * term list) list) * local_theory"}
88
+ − 139
+ − 140
In the list of variables passed to @{ML read_specification in Specification}, we have
+ − 141
used the mixfix annotation @{ML NoSyn} to indicate that we do not want to associate any
+ − 142
mixfix syntax with the variable. Moreover, we have only specified the type of \texttt{r},
+ − 143
whereas the type of \texttt{trcl} is computed using type inference.
+ − 144
The local variables \texttt{x}, \texttt{y} and \texttt{z} of the introduction rules
+ − 145
are turned into bound variables with the de Bruijn indices,
+ − 146
whereas \texttt{trcl} and \texttt{r} remain free variables.
+ − 147
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 148
*}
32
+ − 149
53
0c3580c831a4
removed the @{ML ...} antiquotation in favour of @{ML_open ...x}
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 150
text {*
88
+ − 151
+ − 152
\paragraph{Parsers for theory syntax}
32
+ − 153
88
+ − 154
Although the function @{ML add_inductive in SimpleInductivePackage} parses terms and types, it still
+ − 155
cannot be used to invoke the package directly from within a theory document.
+ − 156
In order to do this, we have to write another parser. Before we describe
+ − 157
the process of writing parsers for theory syntax in more detail, we first
+ − 158
show some examples of how we would like to use the inductive definition
+ − 159
package.
32
+ − 160
88
+ − 161
+ − 162
The definition of the transitive closure should look as follows:
32
+ − 163
*}
+ − 164
+ − 165
simple_inductive
+ − 166
trcl for r :: "'a \<Rightarrow> 'a \<Rightarrow> bool"
+ − 167
where
+ − 168
base: "trcl r x x"
+ − 169
| step: "trcl r x y \<Longrightarrow> r y z \<Longrightarrow> trcl r x z"
+ − 170
(*<*)
+ − 171
thm trcl_def
+ − 172
thm trcl.induct
+ − 173
thm base
+ − 174
thm step
+ − 175
thm trcl.intros
+ − 176
+ − 177
lemma trcl_strong_induct:
+ − 178
assumes trcl: "trcl r x y"
+ − 179
and I1: "\<And>x. P x x"
+ − 180
and I2: "\<And>x y z. P x y \<Longrightarrow> trcl r x y \<Longrightarrow> r y z \<Longrightarrow> P x z"
+ − 181
shows "P x y"
+ − 182
proof -
+ − 183
from trcl
+ − 184
have "P x y \<and> trcl r x y"
+ − 185
proof induct
+ − 186
case (base x)
+ − 187
from I1 and trcl.base show ?case ..
+ − 188
next
+ − 189
case (step x y z)
+ − 190
then have "P x y" and "trcl r x y" by simp_all
+ − 191
from `P x y` `trcl r x y` `r y z` have "P x z"
+ − 192
by (rule I2)
+ − 193
moreover from `trcl r x y` `r y z` have "trcl r x z"
+ − 194
by (rule trcl.step)
+ − 195
ultimately show ?case ..
+ − 196
qed
+ − 197
then show ?thesis ..
+ − 198
qed
+ − 199
(*>*)
+ − 200
88
+ − 201
text {* Even and odd numbers can be defined by *}
32
+ − 202
+ − 203
simple_inductive
+ − 204
even and odd
+ − 205
where
+ − 206
even0: "even 0"
+ − 207
| evenS: "odd n \<Longrightarrow> even (Suc n)"
+ − 208
| oddS: "even n \<Longrightarrow> odd (Suc n)"
+ − 209
(*<*)
+ − 210
thm even_def odd_def
+ − 211
thm even.induct odd.induct
+ − 212
thm even0
+ − 213
thm evenS
+ − 214
thm oddS
+ − 215
thm even_odd.intros
+ − 216
(*>*)
+ − 217
88
+ − 218
text {* The accessible part of a relation can be introduced as follows: *}
32
+ − 219
+ − 220
simple_inductive
+ − 221
accpart for r :: "'a \<Rightarrow> 'a \<Rightarrow> bool"
+ − 222
where
+ − 223
accpartI: "(\<And>y. r y x \<Longrightarrow> accpart r y) \<Longrightarrow> accpart r x"
+ − 224
(*<*)
+ − 225
thm accpart_def
+ − 226
thm accpart.induct
+ − 227
thm accpartI
+ − 228
(*>*)
+ − 229
+ − 230
text {*
88
+ − 231
Moreover, it should also be possible to define the accessible part
+ − 232
inside a locale fixing the relation @{text r}:
32
+ − 233
*}
+ − 234
+ − 235
locale rel =
+ − 236
fixes r :: "'a \<Rightarrow> 'a \<Rightarrow> bool"
+ − 237
+ − 238
simple_inductive (in rel) accpart'
+ − 239
where
+ − 240
accpartI': "\<And>x. (\<And>y. r y x \<Longrightarrow> accpart' y) \<Longrightarrow> accpart' x"
+ − 241
(*<*)
+ − 242
context rel
+ − 243
begin
+ − 244
+ − 245
thm accpartI'
+ − 246
thm accpart'.induct
+ − 247
+ − 248
end
+ − 249
+ − 250
thm rel.accpartI'
+ − 251
thm rel.accpart'.induct
+ − 252
+ − 253
(*>*)
+ − 254
+ − 255
text {*
+ − 256
88
+ − 257
In this context, it is important to note that Isabelle distinguishes
+ − 258
between \emph{outer} and \emph{inner} syntax. Theory commands such as
+ − 259
\isa{\isacommand{simple{\isacharunderscore}inductive} $\ldots$ \isacommand{for} $\ldots$ \isacommand{where} $\ldots$}
+ − 260
belong to the outer syntax, whereas items in quotation marks, in particular
+ − 261
terms such as @{text [source] "trcl r x x"} and types such as
+ − 262
@{text [source] "'a \<Rightarrow> 'a \<Rightarrow> bool"} belong to the inner syntax.
+ − 263
Separating the two layers of outer and inner syntax greatly simplifies
+ − 264
matters, because the parser for terms and types does not have to know
+ − 265
anything about the possible syntax of theory commands, and the parser
+ − 266
for theory commands need not be concerned about the syntactic structure
+ − 267
of terms and types.
+ − 268
+ − 269
\medskip
+ − 270
\noindent
+ − 271
The syntax of the \isa{\isacommand{simple{\isacharunderscore}inductive}} command
+ − 272
can be described by the following railroad diagram:
+ − 273
\begin{rail}
32
+ − 274
'simple\_inductive' target? fixes ('for' fixes)? \\
+ − 275
('where' (thmdecl? prop + '|'))?
+ − 276
;
88
+ − 277
\end{rail}
32
+ − 278
88
+ − 279
\paragraph{Functional parsers}
71
+ − 280
88
+ − 281
For parsing terms and types, Isabelle uses a rather general and sophisticated
+ − 282
algorithm due to Earley, which is driven by \emph{priority grammars}.
+ − 283
In contrast, parsers for theory syntax are built up using a set of combinators.
+ − 284
Functional parsing using combinators is a well-established technique, which
+ − 285
has been described by many authors, including Paulson \cite{paulson-ML-91}
+ − 286
and Wadler \cite{Wadler-AFP95}.
+ − 287
The central idea is that a parser is a function of type @{ML_type "'a list -> 'b * 'a list"},
+ − 288
where @{ML_type "'a"} is a type of \emph{tokens}, and @{ML_type "'b"} is a type for
+ − 289
encoding items that the parser has recognized. When a parser is applied to a
+ − 290
list of tokens whose prefix it can recognize, it returns an encoding of the
+ − 291
prefix as an element of type @{ML_type "'b"}, together with the suffix of the list
+ − 292
containing the remaining tokens. Otherwise, the parser raises an exception
+ − 293
indicating a syntax error. The library for writing functional parsers in
+ − 294
Isabelle can roughly be split up into two parts. The first part consists of a
+ − 295
collection of generic parser combinators that are contained in the structure
+ − 296
@{ML_struct Scan} defined in the file @{ML_file "Pure/General/scan.ML"} in the Isabelle
+ − 297
sources. While these combinators do not make any assumptions about the concrete
+ − 298
structure of the tokens used, the second part of the library consists of combinators
+ − 299
for dealing with specific token types.
+ − 300
The following is an excerpt from the signature of @{ML_struct Scan}:
32
+ − 301
88
+ − 302
\begin{table}
+ − 303
@{ML "|| : ('a -> 'b) * ('a -> 'b) -> 'a -> 'b"} \\
+ − 304
@{ML "-- : ('a -> 'b * 'c) * ('c -> 'd * 'e) -> 'a -> ('b * 'd) * 'e"} \\
+ − 305
@{ML "|-- : ('a -> 'b * 'c) * ('c -> 'd * 'e) -> 'a -> 'd * 'e"} \\
+ − 306
@{ML "--| : ('a -> 'b * 'c) * ('c -> 'd * 'e) -> 'a -> 'b * 'e"} \\
+ − 307
@{ML "optional: ('a -> 'b * 'a) -> 'b -> 'a -> 'b * 'a" in Scan} \\
+ − 308
@{ML "repeat: ('a -> 'b * 'a) -> 'a -> 'b list * 'a" in Scan} \\
+ − 309
@{ML "repeat1: ('a -> 'b * 'a) -> 'a -> 'b list * 'a" in Scan} \\
+ − 310
@{ML ">> : ('a -> 'b * 'c) * ('b -> 'd) -> 'a -> 'd * 'c"} \\
+ − 311
@{ML "!! : ('a * string option -> string) -> ('a -> 'b) -> 'a -> 'b"}
+ − 312
\end{table}
71
+ − 313
88
+ − 314
Interestingly, the functions shown above are so generic that they do not
+ − 315
even rely on the input and output of the parser being a list of tokens.
+ − 316
If \texttt{p} succeeds, i.e.\ does not raise an exception, the parser
+ − 317
@{ML "p || q" for p q} returns the result of \texttt{p}, otherwise it returns
+ − 318
the result of \texttt{q}. The parser @{ML "p -- q" for p q} first parses an
+ − 319
item of type @{ML_type "'b"} using \texttt{p}, then passes the remaining tokens
+ − 320
of type @{ML_type "'c"} to \texttt{q}, which parses an item of type @{ML_type "'d"}
+ − 321
and returns the remaining tokens of type @{ML_type "'e"}, which are finally
+ − 322
returned together with a pair of type @{ML_type "'b * 'd"} containing the two
+ − 323
parsed items. The parsers @{ML "p |-- q" for p q} and @{ML "p --| q" for p q}
+ − 324
work in a similar way as the previous one, with the difference that they
+ − 325
discard the item parsed by the first and the second parser, respectively.
+ − 326
If \texttt{p} succeeds, the parser @{ML "optional p x" for p x in Scan} returns the result
+ − 327
of \texttt{p}, otherwise it returns the default value \texttt{x}. The parser
+ − 328
@{ML "repeat p" for p in Scan} applies \texttt{p} as often as it can, returning a possibly
+ − 329
empty list of parsed items. The parser @{ML "repeat1 p" for p in Scan} is similar,
+ − 330
but requires \texttt{p} to succeed at least once. The parser
+ − 331
@{ML "p >> f" for p f} uses \texttt{p} to parse an item of type @{ML_type "'b"}, to which
+ − 332
it applies the function \texttt{f} yielding a value of type @{ML_type "'d"}, which
+ − 333
is returned together with the remaining tokens of type @{ML_type "'c"}.
+ − 334
Finally, @{ML "!!"} is used for transforming exceptions produced by parsers.
+ − 335
If \texttt{p} raises an exception indicating that it cannot parse a given input,
+ − 336
then an enclosing parser such as
+ − 337
@{ML [display] "q -- p || r" for p q r}
+ − 338
will try the alternative parser \texttt{r}. By writing
+ − 339
@{ML [display] "q -- !! err p || r" for err p q r}
+ − 340
instead, one can achieve that a failure of \texttt{p} causes the whole parser to abort.
+ − 341
The @{ML "!!"} operator is similar to the \emph{cut} operator in Prolog, which prevents
+ − 342
the interpreter from backtracking. The \texttt{err} function supplied as an argument
+ − 343
to @{ML "!!"} can be used to produce an error message depending on the current
+ − 344
state of the parser, as well as the optional error message returned by \texttt{p}.
+ − 345
+ − 346
So far, we have only looked at combinators that construct more complex parsers
+ − 347
from simpler parsers. In order for these combinators to be useful, we also need
+ − 348
some basic parsers. As an example, we consider the following two parsers
+ − 349
defined in @{ML_struct Scan}:
+ − 350
+ − 351
\begin{table}
+ − 352
@{ML "one: ('a -> bool) -> 'a list -> 'a * 'a list" in Scan} \\
+ − 353
@{ML "$$ : string -> string list -> string * string list"}
+ − 354
\end{table}
+ − 355
+ − 356
The parser @{ML "one pred" for pred in Scan} parses exactly one token that
+ − 357
satisfies the predicate \texttt{pred}, whereas @{ML "$$ s" for s} only
+ − 358
accepts a token that equals the string \texttt{s}. Note that we can easily
+ − 359
express @{ML "$$ s" for s} using @{ML "one" in Scan}:
+ − 360
@{ML [display] "one (fn s' => s' = s)" for s in Scan}
+ − 361
As an example, let us look at how we can use @{ML "$$"} and @{ML "--"} to parse
+ − 362
the prefix ``\texttt{hello}'' of the character list ``\texttt{hello world}'':
+ − 363
+ − 364
@{ML_response [display]
+ − 365
"($$ \"h\" -- $$ \"e\" -- $$ \"l\" -- $$ \"l\" -- $$ \"o\")
+ − 366
[\"h\", \"e\", \"l\", \"l\", \"o\", \" \", \"w\", \"o\", \"r\", \"l\", \"d\"]"
+ − 367
"(((((\"h\", \"e\"), \"l\"), \"l\"), \"o\"), [\" \", \"w\", \"o\", \"r\", \"l\", \"d\"])
+ − 368
: ((((string * string) * string) * string) * string) * string list"}
71
+ − 369
88
+ − 370
Most of the time, however, we will have to deal with tokens that are not just strings.
+ − 371
The parsers for the theory syntax, as well as the parsers for the argument syntax
+ − 372
of proof methods and attributes use the token type @{ML_type OuterParse.token},
+ − 373
which is identical to @{ML_type OuterLex.token}.
+ − 374
The parser functions for the theory syntax are contained in the structure
+ − 375
@{ML_struct OuterParse} defined in the file @{ML_file "Pure/Isar/outer_parse.ML"}.
+ − 376
In our parser, we will use the following functions:
+ − 377
+ − 378
\begin{table}
+ − 379
@{ML "$$$ : string -> token list -> string * token list" in OuterParse} \\
+ − 380
@{ML "enum1: string -> (token list -> 'a * token list) -> token list ->
+ − 381
'a list * token list" in OuterParse} \\
+ − 382
@{ML "prop: token list -> string * token list" in OuterParse} \\
+ − 383
@{ML "opt_target: token list -> string option * token list" in OuterParse} \\
+ − 384
@{ML "fixes: token list ->
+ − 385
(Binding.binding * string option * mixfix) list * token list" in OuterParse} \\
+ − 386
@{ML "for_fixes: token list ->
+ − 387
(Binding.binding * string option * mixfix) list * token list" in OuterParse} \\
+ − 388
@{ML "!!! : (token list -> 'a) -> token list -> 'a" in OuterParse}
+ − 389
\end{table}
71
+ − 390
88
+ − 391
The parsers @{ML "$$$" in OuterParse} and @{ML "!!!" in OuterParse} are
+ − 392
defined using the parsers @{ML "one" in Scan} and @{ML "!!"} from
+ − 393
@{ML_struct Scan}.
+ − 394
The parser @{ML "enum1 s p" for s p in OuterParse} parses a non-emtpy list of items
+ − 395
recognized by the parser \texttt{p}, where the items are separated by \texttt{s}.
+ − 396
A proposition can be parsed using the function @{ML prop in OuterParse}.
+ − 397
Essentially, a proposition is just a string or an identifier, but using the
+ − 398
specific parser function @{ML prop in OuterParse} leads to more instructive
+ − 399
error messages, since the parser will complain that a proposition was expected
+ − 400
when something else than a string or identifier is found.
+ − 401
An optional locale target specification of the form \isa{(\isacommand{in}\ $\ldots$)}
+ − 402
can be parsed using @{ML opt_target in OuterParse}.
+ − 403
The lists of names of the predicates and parameters, together with optional
+ − 404
types and syntax, are parsed using the functions @{ML "fixes" in OuterParse}
+ − 405
and @{ML for_fixes in OuterParse}, respectively.
+ − 406
In addition, the following function from @{ML_struct SpecParse} for parsing
+ − 407
an optional theorem name and attribute, followed by a delimiter, will be useful:
+ − 408
+ − 409
\begin{table}
+ − 410
@{ML "opt_thm_name:
+ − 411
string -> token list -> Attrib.binding * token list" in SpecParse}
+ − 412
\end{table}
+ − 413
+ − 414
We now have all the necessary tools to write the parser for our
+ − 415
\isa{\isacommand{simple{\isacharunderscore}inductive}} command:
+ − 416
+ − 417
@{ML_chunk [display] syntax}
+ − 418
+ − 419
The definition of the parser \verb!ind_decl! closely follows the railroad
+ − 420
diagram shown above. In order to make the code more readable, the structures
+ − 421
@{ML_struct OuterParse} and @{ML_struct OuterKeyword} are abbreviated by
+ − 422
\texttt{P} and \texttt{K}, respectively. Note how the parser combinator
+ − 423
@{ML "!!!" in OuterParse} is used: once the keyword \texttt{where}
+ − 424
has been parsed, a non-empty list of introduction rules must follow.
+ − 425
Had we not used the combinator @{ML "!!!" in OuterParse}, a
+ − 426
\texttt{where} not followed by a list of rules would have caused the parser
+ − 427
to respond with the somewhat misleading error message
+ − 428
+ − 429
\begin{verbatim}
32
+ − 430
Outer syntax error: end of input expected, but keyword where was found
88
+ − 431
\end{verbatim}
+ − 432
+ − 433
rather than with the more instructive message
+ − 434
+ − 435
\begin{verbatim}
32
+ − 436
Outer syntax error: proposition expected, but terminator was found
88
+ − 437
\end{verbatim}
+ − 438
+ − 439
Once all arguments of the command have been parsed, we apply the function
+ − 440
@{ML add_inductive in SimpleInductivePackage}, which yields a local theory
+ − 441
transformer of type @{ML_type "local_theory -> local_theory"}. Commands in
+ − 442
Isabelle/Isar are realized by transition transformers of type
+ − 443
@{ML_type [display] "Toplevel.transition -> Toplevel.transition"}
+ − 444
We can turn a local theory transformer into a transition transformer by using
+ − 445
the function
+ − 446
+ − 447
@{ML [display] "Toplevel.local_theory : string option ->
32
+ − 448
(local_theory -> local_theory) ->
+ − 449
Toplevel.transition -> Toplevel.transition"}
88
+ − 450
+ − 451
which, apart from the local theory transformer, takes an optional name of a locale
+ − 452
to be used as a basis for the local theory.
60
5b9c6010897b
doem tuning and made the cookbook work again with recent changes (CookBook/Package/Ind_Interface.thy needs to be looked at to see what the problem with the new parser type is)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 453
88
+ − 454
(FIXME : needs to be adjusted to new parser type)
60
5b9c6010897b
doem tuning and made the cookbook work again with recent changes (CookBook/Package/Ind_Interface.thy needs to be looked at to see what the problem with the new parser type is)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 455
88
+ − 456
{\it
+ − 457
The whole parser for our command has type
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 458
@{text [display] "OuterLex.token list ->
32
+ − 459
(Toplevel.transition -> Toplevel.transition) * OuterLex.token list"}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 460
which is abbreviated by @{text OuterSyntax.parser_fn}. The new command can be added
88
+ − 461
to the system via the function
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 462
@{text [display] "OuterSyntax.command :
32
+ − 463
string -> string -> OuterKeyword.T -> OuterSyntax.parser_fn -> unit"}
88
+ − 464
which imperatively updates the parser table behind the scenes. }
60
5b9c6010897b
doem tuning and made the cookbook work again with recent changes (CookBook/Package/Ind_Interface.thy needs to be looked at to see what the problem with the new parser type is)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 465
88
+ − 466
In addition to the parser, this
+ − 467
function takes two strings representing the name of the command and a short description,
+ − 468
as well as an element of type @{ML_type OuterKeyword.T} describing which \emph{kind} of
+ − 469
command we intend to add. Since we want to add a command for declaring new concepts,
+ − 470
we choose the kind @{ML "OuterKeyword.thy_decl"}. Other kinds include
+ − 471
@{ML "OuterKeyword.thy_goal"}, which is similar to @{ML thy_decl in OuterKeyword},
+ − 472
but requires the user to prove a goal before making the declaration, or
+ − 473
@{ML "OuterKeyword.diag"}, which corresponds to a purely diagnostic command that does
+ − 474
not change the context. For example, the @{ML thy_goal in OuterKeyword} kind is used
+ − 475
by the \isa{\isacommand{function}} command \cite{Krauss-IJCAR06}, which requires the user
+ − 476
to prove that a given set of equations is non-overlapping and covers all cases. The kind
+ − 477
of the command should be chosen with care, since selecting the wrong one can cause strange
+ − 478
behaviour of the user interface, such as failure of the undo mechanism.
32
+ − 479
*}
+ − 480
+ − 481
(*<*)
+ − 482
end
+ − 483
(*>*)