Major Section: EVENTS
Examples: (theory-invariant (not (and (active-runep '(:rewrite left-to-right)) (active-runep '(:rewrite right-to-left)))) :key my-invariant :error nil)where:; Equivalent to the above: (theory-invariant (incompatible '(:rewrite left-to-right) '(:rewrite right-to-left)) :key my-invariant :error nil)
General Form: (theory-invariant term &key key error)
o
term
is a term that uses no variables other thanens
andstate
;o
key
is an arbitrary ``name'' for this invariant (if omitted, an integer is generated and used); ando
:error
specifies the action to be taken when an invariant is violated -- eithernil
if a warning is to be printed, elset
(the default) if an error is to be caused.
Theory-invariant
is an event that adds to or modifies the table
of user-supplied theory invariants that are checked each time a theory
expression is evaluated.
The theory invariant mechanism is provided via a table
(see table) named theory-invariant-table
. In fact, the
theory-invariant
``event'' is just a macro that expands into a use of the
table
event. More general access to the theory-invariant
table is provided by table
itself. For example, the table
can be inspected or cleared with table
; you can clear an individual
theory invariant by setting the invariant to t
, or eliminate all theory
invariants with the command (table theory-invariant-table nil nil :clear)
.
Theory-invariant-table
maps arbitrary keys to records containing terms
that mention, at most, the variables ens
and state
. Every time an
alleged theory expression is evaluated, e.g., in the in-theory
event or
:
in-theory
hint, each of the terms in theory-invariant-table
is
evaluated with ens
bound to a so-called ``enabled structure'' obtained
from the theory expression and state
bound to the current ACL2 state
(see state). Users generally need not know about the enabled structure,
other than that it can be accessed using the macros active-runep
and
incompatible
; see active-runep and see incompatible. If the result is
nil
, a message is printed and an error occurs (except, only a warning
occurs if :error nil
is specified). Thus, the table can be thought
of as a list of conjuncts. Each term
in the table has a ``name,''
which is just the key under which the term is stored. When a theory violates
the restrictions specified by some term, both the name and the term are
printed. By calling theory-invariant
with a new term but the same name,
you can overwrite that conjunct of the theory invariant; but see the Local
Redefinition Caveat at the end of this note. You may want to avoid using
explicit names, since otherwise the subsequent inclusion of another book that
defines a theory invariant with the same name will override your theory
invariant.
Theory invariants are particularly useful in the context of large rule sets intended for re-use. Such sets often contain conflicting rules, e.g., rules that are to be enabled when certain function symbols are disabled, rules that rewrite in opposite directions and thus loop if simultaneously enabled, groups of rules which should be enabled in concert, etc. The developer of such rule sets understands these restrictions and probably documents them. The theory invariant mechanism allows the developer to codify his restrictions so that the user is alerted when they are violated.
Since theory invariants are arbitrary terms, macros may be used to express commonly used restrictions. For example, executing the event
(theory-invariant (incompatible (:rewrite left-to-right) (:rewrite right-to-left)))would subsequently cause an error any time the current theory contained both of the two runes shown. Of course, incompatible is just defined as a macro. Its definition may be inspected with
:pe incompatible
.
In order for a theory-invariant
event to be accepted, the proposed theory
invariant must be satisfied by the current theory (see current-theory). The
value returned upon successful execution of the event is the key (whether
user-supplied or generated).
Local Redefinition Caveat. Care needs to be taken when redefining a theory invariant in a local context. Consider the following example.
(theory-invariant (active-runep '(:definition binary-append)) :key app-inv)The second pass of the(encapsulate () (local (theory-invariant t :key app-inv)) (in-theory (disable binary-append)) (defthm ...))
encapsulate
will fail, because the
in-theory
event violates the original theory-invariant
and the
local
theory-invariant
is skipped in the second pass of the
encapsulate
. Of course, local
theory-invariant
s in
books can cause the analogous problem in the second (include-book
)
pass of a certify-book
. In both cases, though, the theory invariants
are only checked at the conclusion of the (include-book
or
encapsulate
) event. Indeed, theory invariants are checked at the end of
every event related to theories, including defun
, defthm
,
in-theory
, encapsulate
, and include-book
, except for events
executed on behalf of an include-book
or the second pass of an
encapsulate
.