Major Section: MISCELLANEOUS
This is an advanced feature, originally implmented to help system designers to create ``modes'' that control the way hints are supplied to the theorem prover. Please see default-hints for the much more usual way to install hints that may be applied by default.
Examples: ACL2 !>(override-hints (w state)) ((computed-hint-1 clause keyword-alist processor) (computed-hint-2 clause keyword-alist stable-under-simplificationp))
Override-hints
returns a list of computed hints (see computed-hints)
which, unlike other computed hints, may mention the variable
KEYWORD-ALIST
.
Before reading further, please see hints-and-the-waterfall to review the
basics of how hints are applied during a proof. In particular, we
assume familiarity with the notion of selecting a hint to be applied to the
current goal. If there are override-hints, that hint selection is tentative,
because if it reduced to nil
after the application of override-hints,
then that hint will be skipped and the attempt will continue for selecting an
applicable hint. (Craft your override-hints so that :no-op t
is returned
in such cases instead of nil
, if you don't want the hint to be skipped.)
But we must explain what is meant by ``the application of override-hints'',
and we do that now.
Suppose that there are override-hints when a hint is selected for the current
goal. The hint object selected is a keyword-alist, which is an alternating
list of hint keywords and their values, provided either from an explicit hint
(goal-name :key1 val1 ... :keyn valn)
where the :keyi
are allowed to
be custom hint keywords which are expanded away (see custom-keyword-hints),
or else is the non-nil
result from evaluating a computed hint. Then the
override-hints are applied to that keyword-alist as follows, one at a time,
in order of their occurrence in the list of override-hints (as determined by
the use of set-override-hints
and add-override-hints
). The first
override-hint is evaluated, in the usual manner of evaluating computed hints
but with KEYWORD-ALIST
bound to the above keyword-alist. That evaluation
produces a result that should also be a keyword-alist. Then
KEYWORD-ALIST
is bound to that result, and the second override-hint is
evaluated. This process continues, and the keyword-alist returned by the
final override-hint is the one used when processing the goal at hand. If at
any iteration the keyword-alist fails to satisfy the predicate
keyword-value-listp
or contains the :ERROR
hint keyword, an error
is reported. If the final result is nil
, then the hint is discarded and
the remaining hints are considered as above, regardless of whether the
tentatively selected hint object came from a computed hint or from an
explicit hint.
If finally no hint is selected for the current goal, then KEYWORD-ALIST
is bound to nil
and the override-hints are applied as described above.
But note that this final step is skipped if hint selection is being performed
because stable-under-simplificationp
has just become true, rather than at
the top of the waterfall. (Otherwise the override-hints could easily keep
firing uselessly yet putting us back at the top of the waterfall, with no
change to the given goal, resulting in an infinite loop.)
The :COMPUTED-HINT-REPLACEMENT
keyword is illegal for the value of an
override-hint. But a selected hint may be a computed hint that evaluates to
a keyword-alist beginning with prefix :COMPUTED-HINT-REPLACEMENT val
.
What value does ACL2 return for such a computed hint in the presence of
override-hints? First, this prefix is stripped off before passing the
resulting keyword-alist to the override-hints as described above. If the
result of applying override-hints to that keyword-alist is not nil
, then
the prefix is put back on the front of that resulting keyword-alist after
doing internal processing of the hint, including expansion of any custom
keyword hints. Otherwise, the application of override-hints to the computed
hint is nil
, so this hint is not selected after all.
WARNING: Unlike ordinary computed hints, a value of nil
for an
override-hint is not ignored. That is: When an ordinary computed hint
evaluates to nil
, it is deemed not to apply, and the next available hint
is consulted. But when an override-hint is evaluated, the result is always
supplied for the next binding of the variable KEYWORD-ALIST
, even if that
result is nil
. If you want an override-hint to be a no-op, return as the
expression the variable KEYWORD-ALIST
rather than an expression that
evaluates to nil
.
This feature can be used in order to implement a form of additive hints. Suppose for example that you want a hint that turns off generalization. A simple but inadequate solution is:
(add-default-hints '((quote (:do-not '(generalize)))))The problem is that if there is any explicit hint supplied for a given goal, then it will be the one selected, and the above will be ignored. But suppose that the explicit hint supplied is of the form
("Subgoal x.y" :do-not '(fertilize))
. What we would really want in
this case is to generate the hint for the indicated subgoal that binds
:do-not
to a list indicating that both fertilization _and_ generalization
are disabled for that goal. A solution is to merge, as follows.
(add-override-hints '((let ((tmp (assoc-eq :do-not KEYWORD-ALIST))) (put-assoc-eq :do-not (add-to-set-eq 'generalize (cdr tmp)) KEYWORD-ALIST))))
REMARKS
(1) The utilities add-override-hints
, add-override-hints!
,
set-override-hints
, set-override-hints!
,
remove-override-hints
, and remove-override-hints!
are also
available, in complete analogy to their default-hints versions.
(2) The distributed book hints/basic-tests.lisp
illustrates the use of
override-hints and illuminates a number of corner cases; search in that file
for ``Test override-hints.''
(3) The distributed book hints/merge-hint.lisp
provides support for
merging hints that might be useful for writers of override-hint expressions
(see the examples at the end of that file).
(4) Override-hints are used in the processing of :BACKTRACK
hints
(see hints).