Major Section: MISCELLANEOUS
A ``world'' is a list of triples, each of the form (sym prop . val),
implementing the ACL2 notion of property lists. ACL2 permits the
simultaneous existence of many property list worlds. ``The world''
is often used as a shorthand for ``the ACL2 logical world'' which is
the particular property list world used within the ACL2 system to
maintain the data base of rules.
Common Lisp provides the notion of ``property lists'' by which one
can attach ``properties'' and their corresponding ``values'' to
symbols. For example, one can arrange for the 'color property of
the symbol 'box-14 to be 'purple and the 'color property of the
symbol 'triangle-7 to be 'yellow. Access to property lists is given
via the Common Lisp function get. Thus, (get 'box-14 'color) might
return 'purple. Property lists can be changed via the special form
setf. Thus, (setf (get 'box-14 'color) 'blue) changes the Common
Lisp property list configuration so that (get 'box-14 'color)
returns 'blue. It should be obvious that ACL2 cannot provide this
facility, because Common Lisp's get ``function'' is not a function
of its argument, but instead a function of some implicit state
object representing the property list settings for all symbols.
ACL2 provides the functions getprop and putprop which allow one to
mimic the Common Lisp property list facility. However, ACL2's
getprop takes as one of its arguments a list that is a direct
encoding of what was above called the ``state object representing
the property list settings for all symbols.'' Because ACL2 already
has a notion of ``state'' that is quite distinct from that used
here, we call this property list object a ``world.'' A world is
just a true list of triples. Each triple is of the form
(sym prop . val). This world can be thought of as a slightly
elaborated form of association list and getprop is a slightly
elaborated form of assoc that takes two keys. When getprop is
called on a symbol, s, property p, and world, w, it
scans w for the first triple whose sym is s and prop is
p and returns the corresponding val. Getprop has two
additional arguments, one of which that controls what it returns if
no such sym and prop exist in w, and other other of which
allows an extremely efficient implementation. To set some
property's value for some symbol, ACL2 provides putprop.
(putprop sym prop val w) merely returns a new world, w', in
which (sym prop . val) has been consed onto the front of w,
thus ``overwriting'' the prop value of sym in w to val
and leaving all other properties in w unchanged.
One aspect of ACL2's property list arrangment is that it is possible
to have many different property list worlds. For example, 'box-14
can have 'color 'purple in one world and can have 'color 'yes in
another, and these two worlds can exist simultaneously because
getprop is explicitly provided the world from which the property
value is to be extracted.
The efficiency alluded to above stems from the fact that Common Lisp
provides property lists. Using Common Lisp's provisions behind the
scenes, ACL2 can ``install'' the properties of a given world into
the Common Lisp property list state so as to make retrieval via
getprop very fast in the special case that the world provided to
getprop has been installed. To permit multiple installed worlds,
each of which is permitted to be changed via putprop, ACL2 requires
that worlds be named and these names are used to distinquish
installed versions of the various worlds. At the moment we do not
further document getprop and putprop.
However, the ACL2 system uses a property list world, named
'current-acl2-world, in which to store the succession of user
commands and their effects on the logic. This world is often
referred to in our documentation as ``the world'' though it should
be stressed that the user is permitted to have worlds and ACL2's is
in no way distinguished except that the user is not permitted to
modify it except via event commands. The ACL2 world is part of the
ACL2 state and may be obtained via (w state).
Warning: The ACL2 world is very large. Its length as of this
writing (Version 2.5) is over 40,000 and it grows with each release.
Furthermore, some of the values stored in it are pointers to old
versions of itself. Printing (w state) is something you should
avoid because you likely will not have the patience to await its
completion. For these practical reasons, the only thing you should
do with (w state) is provide it to getprop, as in the form
(getprop sym prop default 'current-acl2-world (w state))to inspect properties within it, or to pass it to ACL2 primitives, such as theory functions, where it is expected.
Some ACL2 command forms, such as theory expressions
(see theories) and the values to be stored in tables
(see table), are permitted to use the variable symbol world
freely with the understanding that when these forms are evaluated
that variable is bound to (w state). Theoretically, this gives
those forms complete knowledge of the current logical configuration
of ACL2. However, at the moment, few world scanning functions have
been documented for the ACL2 user. Instead, supposedly convenient
macro forms have been created and documented. For example,
(current-theory :here), which is the theory expression which returns
the currently enabled theory, actually macroexpands to
(current-theory-fn :here world). When evaluated with world bound to
(w state), current-theory-fn scans the current ACL2 world and
computes the set of runes currently enabled in it.
ld without state -- a short-cut to a parallel universe
Major Section: MISCELLANEOUS
Example Form:
(wormhole t 'interactive-break nil '(value 'hi!))
; Enters a recursive read-eval-print loop
; on a copy of the ``current state'' and
; returns nil!
General Form:
(wormhole pseudo-flg name input form
:current-package ... ; known package name
:ld-skip-proofsp ... ; t, nil or 'include-book
:ld-redefinition-action ; nil or '(:a . :b)
:ld-prompt ... ; nil, t, or some prompt printer fn
:ld-keyword-aliases ... ; an alist pairing keywords to parse info
:ld-pre-eval-filter ... ; :all, :query, or some new name
:ld-pre-eval-print ... ; nil, t, or :never
:ld-post-eval-print ... ; nil, t, or :command-conventions
:ld-evisc-tuple ... ; nil or '(alist nil nil level length)
:ld-error-triples ... ; nil or t
:ld-error-action ... ; :continue, :return, or :error
:ld-query-control-alist ; alist supplying default responses
:ld-verbose ...) ; nil or t
The keyword arguments above are exactly those of ld (see ld)
except that three of ld's keyword arguments are missing: the three
that specify the channels standard-oi, standard-co and proofs-co.
Essentially wormhole is just a call of ld on the current state with
the given keyword arguments. Wormhole always returns nil. The
amazing thing about wormhole is that it calls ld and interacts with
the user even though state is not available as an argument!
Wormhole does this by manufacturing a ``wormhole state,'' a copy of
the ``current state'' (whatever that is) modified so as to contain
some of the wormhole arguments. Ld is called on that wormhole state
with the three ld channels directed to ACL2's ``comment window.'' At
the moment, the comment window is overlaid on the terminal and you
cannot tell when output is going to *standard-co* and when it is
going to the comment window. But we imagine that eventually a
different window will pop up on your screen. In any case, the
interaction provided by this call of ld does not modify the state
``from which'' wormhole was called, it modifies the copied state.
When ld exits (e.g., in response to :q being typed in the comment
window) the wormhole state evaporates and wormhole returns nil.
Logically and actually (from the perspective of the ongoing
computation) nothing has happened except that a ``no-op'' function was
called and returned nil.
The name wormhole is meant to suggest the idea that the function
provides easy access to state in situations where it is apparently
impossible to get state. Thus, for example, if you define the
factorial function, say, except that you sprinkled into its body
appropriate calls of wormhole, then the execution of (factorial 6)
would cause interactive breaks in the comment window. During those
breaks you would apparently be able to inspect the ``current state''
even though factorial does not take state as an argument. The whole
notion of there being a ``current state'' during the evaluation of
(factorial 6) is logically ill-defined. And yet, we know from
practical experience with the sequential computing machines upon
which ACL2 is implemented that there is a ``current state'' (to
which the factorial function is entirely insensitive) and that is
the state to which wormhole ``tunnels.'' A call of wormhole from
within factorial can pass factorial-specific information that is
embedded in the wormhole state and made available for inspection by
the user in an interactive setting. But no information ever flows
out of a wormhole state: wormhole always returns nil.
There are some restrictions about what can be done inside a wormhole. As you
may imagine, we really do not ``copy the current state'' but rather just keep
track of how we modified it and undo those modifications upon exit. An error is
signalled if you try to modify state in an unsupported way. For this same
reason, wormholes do not allow updating of any user-defined single-threaded
objects. See stobj.
There are four arguments to wormhole that need further explanation:
pseudo-flg, name, input, and form. Roughly speaking, the value of
pseudo-flg should be t or nil and indicates whether we are actually
to enter a wormhole or just return nil immediately. The actual
handling of pseudo-flg is more sophisticated and is explained in
detail at the end of this documentation.
Name and input are used as follows. Recall that wormhole copies the
``current state'' and then modifies it slightly to obtain the state
upon which ld is called. We now describe the modifications. First,
the state global variable 'wormhole-name is set to name, which may
be any non-nil ACL2 object but is usually a symbol. Then,
'wormhole-input is set to input, which may be any ACL2 object.
Finally, and inexplicably, 'wormhole-output is set to the value of
'wormhole-output the last time a wormhole named name was exited (or
nil if this is the first time a wormhole named name was entered).
This last aspect of wormholes, namely the preservation of
'wormhole-output, allows all the wormholes of a given name to
communicate with each other.
We can now explain how form is used. The modified state described
above is the state on which ld is called. However, standard-oi --
the input channel from which ld reads commands -- is set so that the
first command that ld reads and evaluates is form. If form returns
an error triple with value :q, i.e., form returns via (value :q),
then no further commands are read, ld exits, and the wormhole exits
and returns nil. But if form returns any other value (or is not an
error triple), then subsequent commands are read from the comment
window.
As usual, the ld-specials affect whether a herald is printed upon
entry, whether form is printed before evaluation, whether a prompt
is printed, how errors are handled, etc. The ld-specials can be
specified with the corresponding arguments to wormhole. It is
standard practice to call wormhole so that the entry to ld and the
evaluation of form are totally silent. Then, tests in form can
inspect the state and decide whether user interaction is desired.
If so, form can appropriately set ld-prompt, ld-error-action, etc.,
print a herald, and then return (value :invisible). Recall
(see ld) that (value :invisible) causes ld not to print a value
for the just executed form. The result of this arrangement is that
whether interaction occurs can be based on tests that are performed
on the wormhole state after (@ wormhole-input) and the last
(@ wormhole-output) are available for inspection. This is
important because outside the wormhole you can access
wormhole-input (you are passing it into the wormhole) but you may
not be able to access the current state (because you might be in
factorial) and you definitely cannot access the wormhole-output of
the last wormhole because it is not part of the ACL2 state. Thus,
if the condition under which you wish to interact depends upon the
state or that part of it preserved from the last wormhole
interaction, that condition can only be tested from within the
wormhole, via form.
It is via this mechanism that break-rewrite (see break-rewrite)
is implemented. To be more precise, the list of monitored runes is
maintained as part of the preserved wormhole-output of the
break-rewrite wormhole. Because it is not part of the normal state,
it may be changed by the user during proofs. That is what allows
you to install new monitors while debugging proofs. But that means
that the list of monitored runes cannot be inspected from outside
the wormhole. Therefore, to decide whether a break is to occur when
a given rule is applied, the rewriter must enter the break-rewrite
wormhole, supplying a form that causes interaction if the given
rule's break condition is satisfied. The user perceives this as
though the wormhole was conditionally entered -- a perception that
is happily at odds with the informed user's knowledge that the list
of monitored runes is not part of the state. In fact, the wormhole
was unconditionally entered and the condition was checked from
within the wormhole, that being the only state in which the
condition is known.
Another illustrative example is available in the implemention of the
monitor command. How can we add a new rune to the list of monitored
runes while in the normal ACL2 state (i.e., while not in a
wormhole)? The answer is: by getting into a wormhole. In
particular, when you type (monitor rune expr) at the top-level of
ACL2, monitor enters the break-rewrite wormhole with a cleverly
designed first form. That form adds rune and expr to the list of
monitored runes -- said list only being available in break-rewrite
wormhole states. Then the first form returns (value :q), which
causes us to exit the wormhole. By using ld-specials that
completely suppress all output during the process, it does not
appear to the user that a wormhole was entered. The moral here is
rather subtle: the first form supplied to wormhole may be the entire
computation you want to perform in the wormhole; it need not just be
a predicate that decides if interaction is to occur. Using
wormholes of different names you can maintain a variety of
``hidden'' data structures that are always accessible (whether
passed in or not). This appears to violate completely the
applicative semantics of ACL2, but it does not: because these data
structures are only accessible via wormholes, it is impossible for
them to affect any ACL2 computation (except in the comment window).
As one might imagine, there is some overhead associated with
entering a wormhole because of the need to copy the current state.
This brings us back to pseudo-flg. Ostensibly, wormhole is a
function and hence all of its argument expressions are evaluated
outside the function (and hence, outside the wormhole it creates)
and then their values are passed into the function where an
appropriate wormhole is created. In fact, wormhole is a macro that
permits the pseudo-flg expression to peer dimly into the wormhole
that will be created before it is created. In particular,
pseudo-flg allows the user to access the wormhole-output that will
be used to create the wormhole state.
This is done by allowing the user to mention the (apparently
unbound) variable wormhole-output in the first argument to wormhole.
Logically, wormhole is a macro that wraps
(let ((wormhole-output nil)) ...)around the expression supplied as its first argument. So logically,
wormhole-output is always nil when the expression is
evaluated. However, actually, wormhole-output is bound to the
value of (@ wormhole-output) on the last exit from a wormhole of
the given name (or nil if this is the first entrance). Thus, the
pseudo-flg expression, while having to handle the possibility
that wormhole-output is nil, will sometimes see non-nil
values. The next question is, of course, ``But how can you get away
with saying that logically wormhole-output is always nil but
actually it is not? That doesn't appear to be sound.'' But it is
sound because whether pseudo-flg evaluates to nil or
non-nil doesn't matter, since in either case wormhole returns
nil. To make that point slightly more formal, imagine that
wormhole did not take pseudo-flg as an argument. Then it
could be implemented by writing
(if pseudo-flg (wormhole name input form ...) nil).Now since wormhole always returns
nil, this expression is
equivalent to (if pseudo-flg nil nil) and we see that the value
of pseudo-flg is irrelevant. So we could in fact allow the user
to access arbitrary information to decide which branch of this if to
take. We allow access to wormhole-output because it is often all
that is needed. We don't allow access to state (unless state is
available at the level of the wormhole call) for technical reasons
having to do with the difficulty of overcoming translate's
prohibition of the sudden appearance of the variable state.
We conclude with an example of the use of pseudo-flg. This example
is a simplification of our implementation of break-rewrite. To
enter break-rewrite at the beginning of the attempted application of
a rule, rule, we use
(wormhole
(and (f-get-global 'brr-mode state)
(member-equal (access rewrite-rule rule :rune)
(cdr (assoc-eq 'monitored-runes wormhole-output))))
'break-rewrite
...)
The function in which this call of wormhole occurs has state as a
formal. The pseudo-flg expression can therefore refer to state to
determine whether 'brr-mode is set. But the pseudo-flg expression
above mentions the variable wormhole-output; this variable is not
bound in the context of the call of wormhole; if wormhole were a
simple function symbol, this expression would be illegal because it
mentions a free variable.
However, it is useful to think of wormhole as a simple function that
evaluates all of its arguments but to also imagine that somehow
wormhole-output is magically bound around the first argument so that
wormhole-output is the output of the last break-rewrite wormhole.
If we so imagine, then the pseudo-flg expression above evaluates
either to nil or non-nil and we will enter the wormhole named
break-rewrite in the latter case.
Now what does the pseudo-flg expression above actually test? We
know the format of our own wormhole-output because we are
responsible for maintaining it. In particular, we know that the
list of monitored runes can be obtained via
(cdr (assoc-eq 'monitored-runes wormhole-output)).Using that knowledge we can design a
pseudo-flg expression which
tests whether (a) we are in brr-mode and (b) the rune of the
current rule is a member of the monitored runes. Question (a) is
answered by looking into the current state. Question (b) is
answered by looking into that part of the about-to-be-created
wormhole state that will differ from the current state. To
reiterate the reason we can make wormhole-output available here
even though it is not in the current state: logically speaking the
value of wormhole-output is irrelevant because it is only used to
choose between two identical alternatives. This example also makes
it clear that pseudo-flg provides no additional functionality.
The test made in the pseudo-flg expression could be moved into
the first form evaluated by the wormhole -- changing the free
variable wormhole-output to (@ wormhole-output) and arranging
for the first form to return (value :q) when the pseudo-flg
expression returns nil. The only reason we provide the
pseudo-flg feature is because it allows the test to be carried
out without the overhead of entering the wormhole.
Wormholes can be used not only in :program mode definitions but also
in :logic mode definitions. Thus, it is possible (though somewhat
cumbersome without investing in macro support) to annotate logical
functions with output facilities that do not require state. These
facilities do not complicate proof obligations. Suppose then that
one doctored a simple function, e.g., APP, so as to do some printing
and then proved that APP is associative. The proof may generate
extraneous output due to the doctoring. Furthermore, contrary to
the theorem proved, execution of the function appears to affect
*standard-co*. To see what the function ``really'' does when
evaluated, enter raw lisp and set the global variable
*inhibit-wormhole-activityp* to t.
defun
Major Section: MISCELLANEOUS
Common Lisp's defun function does not easily allow one to pass extra
arguments such as ``hints''. ACL2 therefore supports a peculiar new
declaration (see declare) designed explicitly for passing
additional arguments to defun via a keyword-like syntax.
The following declaration is nonsensical but does illustrate all of
the xargs keywords:
(declare (xargs :guard (symbolp x)
:measure (- i j)
:stobjs ($s)
:well-founded-relation my-wfr
:hints (("Goal" :in-theory (theory batch1)))
:guard-hints (("Goal" :in-theory (theory batch1)))
:mode :logic
:verify-guards t
:normalize nil
:otf-flg t))
General Form:
(xargs :key1 val1 ... :keyn valn)
where the keywords and their respective values are as shown below.
Note that once ``inside'' the xargs form, the ``extra arguments'' to
defun are passed exactly as though they were keyword arguments.
:GUARD
Value is a term involving only the formals of the function being
defined. The actual guard used for the definition is the
conjunction of all the guards and types (see declare) declared.
:GUARD-HINTS
Value: hints (see hints), to be used during the guard
verification proofs as opposed to the termination proofs of the
defun.
:MEASURE
Value is a term involving only the formals of the function being
defined. This term is indicates what is getting smaller in the
recursion. The well-founded relation with which successive measures
are compared is e0-ord-<.
:STOBJS
Value is either a single stobj name or a true list of stobj names.
Every stobj name among the formals of the function must be listed, if the
corresponding actual is to be treated as a stobj. That is, if a function
uses a stobj name as a formal parameter but the name is not declared among
the :stobjs then the corresponding argument is treated as ordinary.
The only exception to this rule is state: whether you include it
or not, state is always treated as a single-threaded object.
:WELL-FOUNDED-RELATION
Value is a function symbol that is known to be a well-founded
relation in the sense that a rule of class :well-founded-relation
has been proved about it. See well-founded-relation.
:HINTS
Value: hints (see hints), to be used during the termination
proofs as opposed to the guard verification proofs of the defun.
:MODE
Value is :program or :logic, indicating the defun mode of the
function introduced. See defun-mode. If unspecified, the
defun mode defaults to the default defun mode of the current world.
To convert a function from :program mode to :logic mode,
see verify-termination.
:VERIFY-GUARDS
Value is t or nil, indicating whether or not guards are to be
verified upon completion of the termination proof. This flag should
only be t if the :mode is unspecified but the default defun mode is
:logic, or else the :mode is :logic.
:OTF-FLG
Value is a flag indicating ``onward through the fog''
(see otf-flg).
:NORMALIZE
Value is a flag telling defun whether to propagate if tests
upward. Since the default is to do so, the value supplied is only of
interest when it is nil.
(see defun).