The purpose of this chapter is fourfold:
The constructors of LUTINS are fixed, but you can define quasi-constructors which effectively serve as additional constructors. Quasi-constructors are desirable for several reasons:
Quasi-constructors are implemented as ``macro/abbreviations.'' For
example, the quasi-constructor quasi-equals10.1 is defined by the following
biconditional:
When the preparsed string representation of an expression (``preparsed string'' for short) of the form is parsed, is treated as a macro with the list of arguments E1,E2: an internal representation of the expression (``internal expression'') is built from the preparsed string as if it had the form . When an internal expression of the form is printed, is used as an abbreviation: the printed string representation of the expression (``printed string'') is generated from the internal expression as if the latter had the form . In other words, in string representation of the expression looks like , an operator applied to a list of two arguments, but it is actually represented internally as .
Abstractly, a quasi-constructor definition consists of three components: a name, a list of schema variables, and a schema. In our example above, quasi-equals is the name, E1,E2 is the list of schema variables, and the right-hand side of the biconditional above is the schema. A quasi-constructor is defined by a user with the def-quasi-constructor form. The list of schema variables and the schema are represented together by a lambda-expression which is specified by a string and a name of a language or theory. The variables of the lambda-expression represent the list of schema variables, and the body of the lambda-expression represents the schema.
For instance, quasi-equals could be defined by:
(def-quasi-constructor QEQUALS "lambda(e1,e2:ind, #(e1) or #(e2) implies e1 = e2)" (language the-kernel-theory))The name of the quasi-constructor is qequals, and the lambda-expression is the expression specified by the string in the-kernel-theory. After this form has been evaluated, an expression of the form is well-formed in any language containing the language of the-kernel-theory, provided A and B are well-formed expressions of the same type of kind . Separate from the definition, special syntax may be defined for parsing and printing qequals (e.g., as the infix symbol ).
The quasi-constructor quasi-equals is not actually defined using a def-quasi-constructor form in IMPS. It is one of a small number of ``system quasi-constructors'' which have been directly defined by the IMPS implementors. A system quasi-constructor cannot be defined using the def-quasi-constructor form because the schema of the quasi-constructor cannot be fully represented as a LUTINS lambda-expression. This is usually because one or more variables of the schema variables ranges over function expressions of variable arity or over expressions of both kind and . For example, is not well-defined if A and B are of kind , but is well-defined as long as A and B have the same type (regardless of its kind). The major system quasi-constructors are listed in Table 10.1.
|
There are two modes for reasoning with a quasi-constructor Q. In the enabled mode the internal structure of Q is ignored. For example, in this mode, when an expression Q(E1,..,En) is simplified, only the parts of the internal expression corresponding to the arguments E1,..,En are simplified, and the part corresponding to Q is ``skipped.'' Similarly, when a macete is applied to an expression Q(E1,..,En), subexpressions located in the part of the internal expression corresponding to Q are ignored. In this mode, quasi-constructors are intended to behave as if they were ordinary constructors.
In the disabled mode, the internal structure of Q has no special status. That is, deduction is performed on internal expressions as if Q was never defined. (However, in this mode expressions involving Q will still be printed using Q as an abbreviation.) The mode is activated by ``disabling Q,'' and it inactivated by ``enabling Q.'' The disabled mode is used for proving basic properties about Q. Once a good set of basic properties are proven and formalized as theorems, there is usually little need for the disabled mode. Most quasi-constructors are intended to be employed in multiple theories. Hence, you will usually want to install a theorem about a quasi-constructor with the usage transportable-macete.
For a few of the interactive proof commands, there is a dual command with the word ``insistent'' put somewhere into the command's name. For example, the dual of simplify is the simplify-insistently. Calling the dual of a command C is equivalent to disabling all quasi-constructors and then calling Citself. In other words, the dual commands behave as if there were no quasi-constructors at all. These ``insistent'' commands are intended to be used sparingly because they can disturb the internal structure corresponding to a quasi-constructor, creating a new internal expression that can no longer be abbreviated by the quasi-constructor. In visual terms, the quasi-constructor ``explodes.''
One of the advantages of working in a logic like LUTINS, with a rich structure of functions, is that generic objects like sets and sequences can be represented directly in the logic as certain kinds of functions. For instance, sets are represented in IMPS as indicators, which are similar to characteristic functions, except that x is a ``member'' of an indicator f iff f(x) is defined. Operators on indicators and other functions representing generic objects are formalized in IMPS as quasi-constructors, and theorems about these operators are proved in ``generic theories'' that contain neither constants nor axioms (except for possibly the axioms of the theory h-o-real-arithmetic). Consequently, reasoning is performed in generic theories using only the purely logical apparatus of LUTINS (and possibly h-o-real-arithmetic). Moreover, theorems about generic objects are easy to apply in other theories since the operators, as quasi-constructors, are polymorphic and since the theory interpretations involved usually have no obligations to check.
(view-expr "1/0==?zz" (language-name h-o-real-arithmetic) no-quasi-constructors)is evaluated, the expression is printed as
(#(1/0) or #(?zz)) implies 1/0=?zz.
q{e1,...,en}
, where q is
a quasi-constructor, is parsed exactly like q(e1,...,en)
. In
addition, the internal expression is always printed like
q{e1,...,en}
, unless you have defined a special print syntax
for q.
with(f:[ind,ind], forall(x:ind, #(f(x))))It parses into an internal expression E1 which is printed as the string S2
with(f:[ind,ind],total_q{f,[ind,ind]})with quasi-constructor abbreviations and is printed as S1 without quasi-constructor abbreviations. However, S2 parses into an internal expression E2 which is printed as S2 with quasi-constructor abbreviations and is printed as the string S3
with(f:[ind,ind],forall(x_0:ind,#(f(x_0))))without quasi-constructor abbreviations. That is, the two internal expressions are the same except for the name of the single bound variable.