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).