This is documentation for ACL2 Version 3.2
Copyright (C) 2007  University of Texas at Austin

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Written by:  Matt Kaufmann and J Strother Moore
Department of Computer Sciences
University of Texas at Austin
Austin, TX 78712-1188 U.S.A.

RULE-CLASSES    adding rules to the data base

     General Form:
     a true list of rule class objects as defined below

     Special Cases:
     a symbol abbreviating a single rule class object

ACL2 provides users with the ability to create a number of different
kinds of rules, including (conditional) rewrite rules but also
including others.  Don't be put off by the long description to follow;
usually, you'll probably want to use rewrite rules.  More on this below.

A rule class object is either one of the :class keywords or else is a
list of the form shown below.  Those fields marked with "(!)"  are
required when the :class is as indicated.

     (:class
       :COROLLARY term
       :TRIGGER-FNS (fn1 ... fnk) ; provided :class = :META (!)
       :TRIGGER-TERMS (t1 ... tk) ; provided :class = :FORWARD-CHAINING
                                  ;       or :class = :LINEAR
       :TYPE-SET n                ; provided :class = :TYPE-SET-INVERTER
       :TYPED-TERM term           ; provided :class = :TYPE-PRESCRIPTION
       :CLIQUE (fn1 ... fnk)      ; provided :class = :DEFINITION
       :CONTROLLER-ALIST alist    ; provided :class = :DEFINITION
       :INSTALL-BODY directive    ; provided :class = :DEFINITION
       :LOOP-STOPPER alist        ; provided :class = :REWRITE
       :PATTERN term              ; provided :class = :INDUCTION (!)
       :CONDITION term            ; provided :class = :INDUCTION
       :SCHEME term               ; provided :class = :INDUCTION (!)
       :MATCH-FREE all-or-once    ; provided :class = :REWRITE
                                          or :class = :LINEAR
                                          or :class = :FORWARD-CHAINING
       :BACKCHAIN-LIMIT-LST limit ; provided :class = :REWRITE
                                          or :class = :META
                                          or :class = :LINEAR
       :HINTS hints               ; provided instrs = nil
       :INSTRUCTIONS instrs       ; provided  hints = nil
       :OTF-FLG flg)

When rule class objects are provided by the user, most of the fields
are optional and their values are computed in a context sensitive way.
When a :class keyword is used as a rule class object, all relevant
fields are determined contextually.  Each rule class object in
:rule-classes causes one or more rules to be added to the data base.
The :class keywords are documented individually under the following
names.  Note that when one of these names is used as a :class, it is
expected to be in the keyword package (i.e., the names below should be
preceded by a colon but the ACL2 documentation facilities do not permit
us to use keywords below).

Before we get into the discussion of rule classes, let us return to an
important point.  In spite of the large variety of rule classes
available, at present we recommend that new ACL2 users rely almost
exclusively on (conditional) rewrite rules.  A reasonable but slightly
bolder approach is to use :type-prescription and :forward-chaining
rules for "type-theoretic" rules, especially ones whose top-level
function symbol is a common one like true-listp or consp; see
TYPE-PRESCRIPTION and see FORWARD-CHAINING.  However, the
rest of the rule classes are really not intended for widespread use,
but rather are mainly for experts.

We expect that we will write more about the question of which kind of
rule to use.  For now:  when in doubt, use a :rewrite rule.

:Rule-classes is an optional keyword argument of the defthm (and
defaxiom) event.  In the following, let name be the name of the event
and let thm be the formula to be proved or added as an axiom.

If :rule-classes is not specified in a defthm (or defaxiom) event, it
is as though :rule-classes ((:rewrite)) had been used.  Use
:rule-classes nil to specify that no rules are to be generated.

If :rule-classes class is specified, where class is a non-nil symbol,
it is as though :rule-classes ((class)) had been used.  Thus,
:rule-classes :forward-chaining is equivalent to :rule-classes
((:forward-chaining)).

We therefore now consider :rule-classes as a true list.  If any element
of that list is a keyword, replace it by the singleton list containing
that keyword.  Thus, :rule-classes (:rewrite :elim) is the same as
:rule-classes ((:rewrite) (:elim)).

Each element of the expanded value of :rule-classes must be a true list
whose car is one of the rule class keyword tokens listed above, e.g.,
:rewrite, :elim, etc., and whose cdr is a "keyword alist" alternately
listing keywords and values.  The keywords in this alist must be taken
from those shown below.  They may be listed in any order and most may
be omitted, as specified below.

     :Corollary -- its value, term, must be a term.  If omitted, this
     field defaults to thm.  The :corollary of a rule class object is
     the formula actually used to justify the rule created and thus
     determines the form of the rule.  Nqthm provided no similar
     capability: each rule was determined by thm, the theorem or axiom
     added.  ACL2 permits thm to be stated "elegantly" and then allows
     the :corollary of a rule class object to specify how that elegant
     statement is to be interpreted as a rule.  For the rule class
     object to be well-formed, its (defaulted) :corollary, term, must
     follow from thm.  Unless term is trivially implied by thm, using
     little more than propositional logic, the formula (implies thm
     term) is submitted to the theorem prover and the proof attempt
     must be successful.  During that proof attempt the values of
     :hints, :instructions, and :otf-flg, as provided in the rule class
     object, are provided as arguments to the prover.  Such auxiliary
     proofs give the sort of output that one expects from the prover.
     However, as noted above, corollaries that follow trivially are not
     submitted to the prover; thus, such corollaries cause no prover
     output.

     Note that before term is stored, all calls of macros in it are
     expanded away.  See TRANS.

     :Hints, :instructions, :otf-flg -- the values of these fields must
     satisfy the same restrictions placed on the fields of the same
     names in defthm.  These values are passed to the recursive call of
     the prover used to establish that the :corollary of the rule class
     object follows from the theorem or axiom thm.

     :Type-set -- this field may be supplied only if the :class is
     :type-set-inverter.  When provided, the value must be a type-set,
     an integer in a certain range.  If not provided, an attempt is
     made to compute it from the corollary.  See
     TYPE-SET-INVERTER.

     :Typed-term -- this field may be supplied only if the :class is
     :type-prescription.  When provided, the value is the term for which
     the :corollary is a type-prescription lemma.  If no :typed-term is
     provided in a :type-prescription rule class object, we try to
     compute heuristically an acceptable term.  See
     TYPE-PRESCRIPTION.

     :Trigger-terms -- this field may be supplied only if the :class is
     :forward-chaining or :linear.  When provided, the value is a list
     of terms, each of which is to trigger the attempted application of
     the rule.  If no :trigger-terms is provided, we attempt to compute
     heuristically an appropriate set of triggers.  See
     FORWARD-CHAINING or see LINEAR.

     :Trigger-fns -- this field must (and may only) be supplied if the
     :class is :meta.  Its value must be a list of function symbols.
     Terms with these symbols trigger the application of the rule.  See
     META.

     :Clique and :controller-alist -- these two fields may only be
     supplied if the :class is :definition.  If they are omitted, then
     ACL2 will attempt to guess them.  Suppose the :corollary of the
     rule is (implies hyp (equiv (fn a1 ... an) body)).  The value of
     the :clique field should be a true list of function symbols, and if
     non-nil must include fn.  These symbols are all the members of the
     mutually recursive clique containing this definition of fn.  That
     is, a call of any function in :clique is considered a "recursive
     call" for purposes of the expansion heuristics.  The value of the
     :controller-alist field should be an alist that maps each function
     symbol in the :clique to a list of t's and nil's of length equal to
     the arity of the function.  For example, if :clique consists of
     just two symbols, fn1 and fn2, of arities 2 and 3 respectively,
     then ((fn1 t nil) (fn2 nil t t)) is a legal value of
     :controller-alist.  The value associated with a function symbol in
     this alist is a "mask" specifying which argument slots of the
     function "control" the recursion for heuristic purposes.  Sloppy
     choice of :clique or :controller-alist can result in infinite
     expansion and stack overflow.

     :Install-body -- this field may only be supplied if the :class is
     :definition.  Its value must be t, nil, or the default,
     :normalize.  A value of t or :normalize will cause ACL2 to install
     this rule as the new body of the function being "defined" (fn in
     the paragraph just above); hence this definition will be installed
     for future :expand hints.  Furthermore, if this field is omitted
     or the value is :normalize, then this definition will be
     simplified using the so-called "normalization" procedure that is
     used when processing definitions made with defun.  You must
     explicitly specify :install-body nil in the following cases: fn
     (as above) is a member of the value of constant
     *definition-minimal-theory*, the arguments are not a list of
     distinct variables, equiv (as above) is not equal, or there are
     free variables in the hypotheses or right-hand side (see
     FREE-VARIABLES).  However, supplying :install-body nil will not
     affect the rewriter's application of the :definition rule, other
     than to avoid using the rule to apply :expand hints.  If a
     definition rule equates (f a1 ... ak) with body but there are
     hypotheses, hyps, then :expand hints will replace terms (f term1
     ... termk) by corresponding terms (if hyps body (hide (f term1 ...
     termk))).

     :Loop-stopper -- this field may only be supplied if the class is
     :rewrite.  Its value must be a list of entries each consisting of
     two variables followed by a (possibly empty) list of functions, for
     example ((x y binary-+) (u v foo bar)).  It will be used to
     restrict application of rewrite rules by requiring that the list
     of instances of the second variables must be "smaller" than the
     list of instances of the first variables in a sense related to the
     corresponding functions listed; see LOOP-STOPPER.  The
     list as a whole is allowed to be nil, indicating that no such
     restriction shall be made.  Note that any such entry that contains
     a variable not being instantiated, i.e., not occurring on the left
     side of the rewrite rule, will be ignored.  However, for
     simplicity we merely require that every variable mentioned should
     appear somewhere in the corresponding :corollary formula.

     :Pattern, :Condition, :Scheme -- the first and last of these fields
     must (and may only) be supplied if the class is :induction.
     :Condition is optional but may only be supplied if the class is
     :induction.  The values must all be terms and indicate,
     respectively, the pattern to which a new induction scheme is to be
     attached, the condition under which the suggestion is to be made,
     and a term which suggests the new scheme.  See INDUCTION.

     :Match-free -- this field must be :all or :once and may be
     supplied only if the :class is either :rewrite, :linear, or
     :forward-chaining.  See FREE-VARIABLES for a description
     of this field.  Note: Although this field is intended to be used
     for controlling retries of matching free variables in hypotheses,
     it is legal to supply it even if there are no such free variables.
     This can simplify the automated generation of rules, but note
     that when :match-free is supplied, the warning otherwise provided
     for the presence of free variables in hypotheses will be
     suppressed.

     Backchain-limit-lst -- this field may be supplied only if the
     :class is either :rewrite, :meta, or :linear and only one rule is
     generated from the formula.  Its value must be nil; a non-negative
     integer; or, except in the case of :meta rules, a true list each
     element of which is either nil or a non-negative integer.  If it
     is a list, its length must be equal to the number of hypotheses of
     the rule and each item in the list is the "backchain limit"
     associated with the corresponding hypothesis.  If
     backchain-limit-lst is a non-negative integer, it is defaulted to
     a list of the appropriate number of repetions of that integer.
     The backchain limit of a hypothesis is used to limit the effort
     that ACL2 will expend when relieving the hypothesis.  If it is
     NIL, no new limits are imposed; if it is an integer, the
     hypothesis will be limited to backchaining at most that many
     times.  Note that backchaining may be further limited by a global
     backchain-limit; see BACKCHAIN-LIMIT for details.  For a
     different way to reign in the rewriter, see
     REWRITE-STACK-LIMIT.  Jared Davis has pointed out that you can
     set this field to 0 to avoid any attempt to relieve forced
     hypotheses, which can lead to a significant speed-up in some cases.

Once thm has been proved (in the case of defthm) and each rule class
object has been checked for well-formedness (which might require
additional proofs), we consider each rule class object in turn to
generate and add rules.  Let :class be the class keyword token of the
ith class object (counting from left to right).  Generate the rune
(:class name . x), where x is nil if there is only one class and
otherwise x is i.  Then, from the :corollary of that object, generate
one or more rules, each of which has the name (:class name . x).  See
the :doc entry for each rule class to see how formulas determine rules.
Note that it is in principle possible for several rules to share the
same name; it happens whenever a :corollary determines more than one
rule.  This in fact only occurs for :rewrite, :linear, and
:forward-chaining class rules and only then if the :corollary is
essentially a conjunction.  (See the documentation for rewrite, linear,
or forward-chaining for details.)

BUILT-IN-CLAUSES    to build a clause into the simplifier

See RULE-CLASSES for a general discussion of rule classes and
how they are used to build rules from formulas.  A :built-in-clause
rule can be built from any formula other than propositional
tautologies.  Roughly speaking, the system uses the list of built-in
clauses as the first method of proof when attacking a new goal.  Any
goal that is subsumed by a built in clause is proved "silently."

ACL2 maintains a set of "built-in" clauses that are used to
short-circuit certain theorem proving tasks.  We discuss this at length
below.  When a theorem is given the rule class :built-in-clause ACL2
flattens the implies and and structure of the :corollary formula so as
to obtain a set of formulas whose conjunction is equivalent to the
given corollary.  It then converts each of these to clausal form and
adds each clause to the set of built-in clauses.

For example, the following :corollary (regardless of the definition of
abl)

     (and (implies (and (true-listp x)
                        (not (equal x nil)))
                   (< (acl2-count (abl x))
                      (acl2-count x)))
          (implies (and (true-listp x)
                        (not (equal nil x)))
                   (< (acl2-count (abl x))
                      (acl2-count x))))

will build in two clauses,

     {(not (true-listp x))
      (equal x nil)
      (< (acl2-count (abl x)) (acl2-count x))}

and

     {(not (true-listp x))
      (equal nil x)
      (< (acl2-count (abl x)) (acl2-count x))}.

We now give more background.

Recall that a clause is a set of terms, implicitly representing the
disjunction of the terms.  Clause c1 is "subsumed" by clause c2 if some
instance of c2 is a subset c1.

For example, let c1 be

     {(not (consp l))
      (equal a (car l))
      (< (acl2-count (cdr l)) (acl2-count l))}.

Then c1 is subsumed by c2, shown below,

     {(not (consp x))
      ; second term omitted here
      (< (acl2-count (cdr x)) (acl2-count x))}

because we can instantiate x in c2 with l to obtain a subset of c1.

Observe that c1 is the clausal form of

     (implies (and (consp l)
                   (not (equal a (car l))))
              (< (acl2-count (cdr l)) (acl2-count l))),

c2 is the clausal form of

     (implies (consp l)
              (< (acl2-count (cdr l)) (acl2-count l)))

and the subsumption property just means that c1 follows trivially from
c2 by instantiation.

The set of built-in clauses is just a set of known theorems in clausal
form.  Any formula that is subsumed by a built-in clause is thus a
theorem.  If the set of built-in theorems is reasonably small, this
little theorem prover is fast.  ACL2 uses the "built-in clause check"
in four places: (1) at the top of the iteration in the prover - thus if
a built-in clause is generated as a subgoal it will be recognized when
that goal is considered, (2) within the simplifier so that no built-in
clause is ever generated by simplification, (3) as a filter on the
clauses generated to prove the termination of recursively defun'd
functions and (4) as a filter on the clauses generated to verify the
guards of a function.

The latter two uses are the ones that most often motivate an extension
to the set of built-in clauses.  Frequently a given formalization
problem requires the definition of many functions which require
virtually identical termination and/or guard proofs.  These proofs can
be short-circuited by extending the set of built-in clauses to contain
the most general forms of the clauses generated by the definitional
schemes in use.

The attentive user might have noticed that there are some recursive
schemes, e.g., recursion by cdr after testing consp, that ACL2 just
seems to "know" are ok, while for others it generates measure clauses
to prove.  Actually, it always generates measure clauses but then
filters out any that pass the built-in clause check.  When ACL2 is
initialized, the clause justifying cdr recursion after a consp test is
added to the set of built-in clauses.  (That clause is c2 above.)

Note that only a subsumption check is made; no rewriting or
simplification is done.  Thus, if we want the system to "know" that cdr
recursion is ok after a negative atom test (which, by the definition of
atom, is the same as a consp test), we have to build in a second
clause.  The subsumption algorithm does not "know" about commutative
functions.  Thus, for predictability, we have built in commuted
versions of each clause involving commutative functions.  For example,
we build in both

     {(not (integerp x))
      (< 0 x)
      (= x 0)
      (< (acl2-count (+ -1 x)) (acl2-count x))}

and the commuted version

     {(not (integerp x))
      (< 0 x)
      (= 0 x)
      (< (acl2-count (+ -1 x)) (acl2-count x))}

so that the user need not worry whether to write (= x 0) or (= 0 x) in
definitions.

:built-in-clause rules added by the user can be enabled and disabled.

CLAUSE-PROCESSOR    make or apply a :clause-processor rule (goal-level simplifier)

Also see DEFINE-TRUSTED-CLAUSE-PROCESSOR for documentation of
an analogous utility that does not require the clause-processor to be
proved correct.  But please read the present documentation before
reading about that utility.  Both utilities designate functions
"clause-processors".  Such functions must be executable -- hence not
constrained by virtue of being introduce in the signature of an
encapsulate -- and must respect stobj and output arity restrictions.
For example, something like (car (mv ...)) is illegal; also see
SIGNATURE.

We begin this documentation with an introduction, focusing on an
example, and then conclude with details.  You might find it most useful
simply to look at the examples in distributed directory
books/clause-processors/; see file Readme.lsp in that directory.

A :clause-processor rule installs a simplifier at the level of goals,
where a goal is represented as a _clause_: a list of terms that is
implicitly viewed as a disjunction (the application of OR).  For
example, if ACL2 prints a goal in the form (implies (and p q) r), then
the clause might be the one-element list containing the internal
representation of this term -- (implies (if p q 'nil) r) -- but more
likely, the corresponding clause is ((not p) (not q) r).  Note that the
members of a clause are _translated_ terms; see TERM.  For
example, they do not contains calls of the macro AND, and constants are
quoted.

Note that clause-processor simplifiers are similar to metafunctions, and
similar efficiency considerations apply.  See META, in
particular the discussion on how to "make a metafunction maximally
efficient."

Unlike rules of class :meta, rules of class :clause-processor must be
applied by explicit :clause-processor hints; they are not applied
automatically (unless by way of computed hints; see
COMPUTED-HINTS).  But :clause-processor rules can be useful in
situations for which it is more convenient to code a simplifier that
manipulates the entire goal clause rather than individual subterms of
terms in the clause.

We begin with a simple illustrative example: a clause-processor that
assumes an alleged fact and creates a separate goal to prove that fact.
We can extend the hypotheses of the current goal with a term by adding
the negation of that term to the clause (disjunctive) representation of
that goal.  So the following returns two clauses: the result of adding
term as a hypothesis to the input clause, as just described, and a
second clause consisting only of that term.

     (defun note-fact-clause-processor (cl term)
       (declare (xargs :guard t)) ; optional, for better efficiency
       (list (cons (list 'not term)
                   cl)
             (list term)))

As with :meta rules, we need to introduce a suitable evaluator; see
DEFEVALUATOR.  Since we expect to reason about the function NOT,
because of its role in note-fact-clause-processor as defined above, we
include NOT in the set of functions known to this evaluator.  We also
include IF, as is often a good idea.

     (defevaluator evl0 evl0-list
       ((not x) (if x y z)))

ACL2 can now prove the following theorem automatically.  (Of course,
:clause-processor rules about clause-processor functions less trivial
than note-fact-clause-processor may require lemmas to be proved first!)
The function disjoin takes a clause and returns its disjunction (the
result of applying OR to its members), and conjoin-clauses applies
disjoin to every element of a given list of clauses and then conjoins
(applies AND) to the corresponding list of resulting terms.

     (defthm correctness-of-note-fact-clause-processor
       (implies (and (pseudo-term-listp cl)
                     (alistp a)
                     (evl0 (conjoin-clauses
                            (note-fact-clause-processor cl term))
                           a))
                (evl0 (disjoin cl) a))
       :rule-classes :clause-processor)

Now let us submit a silly but illustrative example theorem to ACL2, to
show how a corresponding :clause-processor hint is applied.  The hint
says to apply the clause-processor function,
note-fact-clause-processor, to the current goal clause and a "user
hint" as the second argument of that function, in this case (equal a
a).  Thus, a specific variable, clause, is always bound to the current
goal clause for the evaluation of the :clause-processor hint, to
produce a list of clauses.  Since two subgoals are created below, we
know that this list contained two clauses.  Indeed, these are the
clauses returned when note-fact-clause-processor is applied to two
arguments:  the current clause, which is the one-element list ((equal
(car (cons x y)) x)), and the user hint, (equal a a).

     ACL2 !>(thm (equal (car (cons x y))
                        x)
                 :hints
                 (("Goal"
                   :clause-processor
                   (note-fact-clause-processor clause '(equal a a)))))

     [Note:  A hint was supplied for our processing of the goal above.
     Thanks!]

     We now apply the verified :CLAUSE-PROCESSOR function NOTE-FACT-CLAUSE-
     PROCESSOR to produce two new subgoals.

     Subgoal 2
     (IMPLIES (EQUAL A A)
              (EQUAL (CAR (CONS X Y)) X)).

     But we reduce the conjecture to T, by the :executable-counterpart of
     IF and the simple :rewrite rule CAR-CONS.

     Subgoal 1
     (EQUAL A A).

     But we reduce the conjecture to T, by primitive type reasoning.

     Q.E.D.

     Summary
     Form:  ( THM ...)
     Rules: ((:EXECUTABLE-COUNTERPART IF)
             (:EXECUTABLE-COUNTERPART NOT)
             (:FAKE-RUNE-FOR-TYPE-SET NIL)
             (:REWRITE CAR-CONS))
     Warnings:  None
     Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)

     Proof succeeded.
     ACL2 !>

That concludes our introduction to clause-processor rules and hints.
We turn now to detailed documentation.

The signature of a clause-processor function, CL-PROC, must have one of
the following forms.  Here, each st_i is a stobj (possibly state) while
the other parameters and results are not stobjs (see DEFSTOBJ).
Note that there need not be input stobjs in [3] -- i.e., k can be 0 --
and even if there are, there need not be output stobjs.

     [1]  ((CL-PROC cl) => cl-list)

     [2]  ((CL-PROC cl hint) => cl-list)

     [3]  ((CL-PROC cl hint st_1 ... st_k) => (erp cl-list st_i1 ... st_in))

In [3], we think of the first component of the result as an error flag.
Indeed, a proof will instantly abort if that error flag is not nil.

We next discuss the legal forms of :clause-processor rules, followed
below by a discussion of :clause-processor hints.  In the discussion
below, we use lower-case names to represent specific symbols, for
example implies, and we use upper-case names to represent more
arbitrary pieces of syntax (which we will describe), for example, CL.

If a :rule-classes specification includes :clause-processor, then the
corresponding term must have the form

     (implies (and (pseudo-term-listp CL)
                   (alistp A)
                   (EVL (conjoin-clauses <CL-LIST>)
                         A))
              (EVL (disjoin CL) A))

where: EVL is a known evaluator (see DEFEVALUATOR); CL and A are
distinct non-stobj variables; and CL-LIST-EXPR is an expression
representing the clauses returned by the clause-processor function
CL-PROC, whose form depends on the signature of that function, as
follows.  For cases [1] and [2] above, CL-LIST-EXPR is of the form
(CL-PROC CL) or (CL-PROC CL HINT), respectively, where in the latter
case HINT is a non-stobj variable distinct from the variables CL and A.
For case [3], CL-LIST-EXPR is of the form

     (clauses-result (CL-PROC CL HINT st_1 ... st_k))

where the st_i are the specific stobj names mentioned in [3].
Logically, clauses-result returns the cadr if the car is NIL, and
otherwise (for the error case) returns a list containing the empty
(false) clause.  So in the non-error case, clauses-result picks out the
second result, denoted cl-list in [3] above, and in the error case the
implication above trivially holds.

The clause-processor function, CL, must have a guard that ACL2 can
trivially prove from the hypotheses that the first argument of CL is
known to be a pseudo-term-listp and any stobj arguments are assumed to
satisfy their stobj predicates.

Next we specify the legal forms for :clause-processor hints.  These
depend on the signature as described in [1] through [3] above.  Below,
as above, CL-PROC is the clause-processor function, and references to
"clause" refer to that exact variable (not, for example, to cl).  In
each of the three cases, the forms shown for that case are equivalent;
in particular, the :function syntax is simply a convenience for the
final form in each case.

Signature [1], ((cl-proc cl) => cl-list):

     :clause-processor CL-PROC
     :clause-processor (:function CL-PROC)
     :clause-processor (CL-PROC clause)

or any term macroexpanding to (CL-PROC clause).

Signature [2], ((cl-proc cl hint) => cl-list):

     :clause-processor (:function CL-PROC :hint HINT)
     :clause-processor (CL-PROC clause HINT)

or any term macroexpanding to (CL-PROC clause HINT), where HINT is any
term with at most CLAUSE free.

Signature [3], ((CL-PROC cl hint ...) => (erp cl-list ...))

     :clause-processor (:function CL-PROC :hint HINT)
     :clause-processor (CL-PROC clause HINT st_1 ... st_k)

or any term macroexpanding to (CL-PROC clause HINT st_1 ... st_k), where
HINT is any term with at most CLAUSE free.

A :clause-processor hint causes the proof to abort if the result
returned by evaluating the suitable CL-PROC call, as above, is not a
list of clauses, i.e., a list of (translated) term lists.  The proof
also aborts if in case [3] the first (erp) value returned is not nil,
in which case erp is used for printing an error message as follows: if
it is a string, then that string is printed; but if it is a non-empty
true list whose first element is a string, then it is printed as though
by (fmt @0 (list (cons #0 erp)) ...) (see FMT).  Otherwise, a
non-nil erp value causes a generic error message to be printed.

If there is no error as above, but the CL-PROC call returns clause list
whose single element is equal to the input clause, then the hint is
ignored since we are left with the goal with which we started.  In that
case, the other prover processes are then applied as usual.

You can see all current :clause-processor rules by issuing the following
command: (print-clause-processor-rules).

The following paper discusses ACL2 clause-processors at a high level
suitable for a non-ACL2 audience:

     M. Kaufmann, J S. Moore, S. Ray, and E. Reeber, "Integrating
     External Deduction Tools with ACL2."  Proceedings of the 6th
     International Workshop on the Implementation of Logics (IWIL 2006)
     (C. Benzmueller, B. Fischer, and G. Sutcliffe, editors), CEUR
     Workshop Proceedings Vol. 212, Phnom Penh, Cambodia, pp. 7-26,
     November 2006, http://ceur-ws.org/Vol-212/.  Expanded version to
     appear in the Journal of Applied Logic.

COMPOUND-RECOGNIZER    make a rule used by the typing mechanism

See RULE-CLASSES for a general discussion of rule classes and
how they are used to build rules from formulas.  An example :corollary
formula from which a :compound-recognizer rule might be built is:

     Example:
     (implies (alistp x)         When (alistp x) is assumed true,
              (true-listp x))    add the additional hypothesis that x
                                 is of primitive type true-listp.

     General Forms:
     (implies (fn x) concl)               ; (1)
     (implies (not (fn x)) concl)         ; (2)
     (and (implies (fn x) concl1)         ; (3)
          (implies (not (fn x)) concl2))
     (if (fn x) concl1 concl2)            ; (4)
     (iff (fn x) concl)                   ; (5)
     (equal (fn x) concl)                 ; (6)

where fn is a Boolean valued function of one argument, x is a variable
symbol, and the system can deduce some restriction on the primitive
type of x from the assumption that concl holds.  The third restriction
is vague but one way to understand it is to weaken it a little to "and
concl is a non-tautological conjunction or disjunction of the primitive
type recognizers listed below."

The primitive ACL2 types and a suitable primitive recognizing
expression for each are listed below.

       type                suitable primitive recognizer

       zero                (equal x 0)
       negative integers   (and (integerp x) (< x 0))
       positive integers   (and (integerp x) (> x 0))
       negative ratio      (and (rationalp x)
                                (not (integerp x))
                                (< x 0))
       positive ratio      (and (rationalp x)
                                (not (integerp x))
                                (> x 0))
       complex rational    (complex-rationalp x)
       nil                 (equal x nil)
       t                   (equal x t)
       other symbols       (and (symbolp x)
                                (not (equal x nil))
                                (not (equal x t)))
       proper conses       (and (consp x)
                                (true-listp x))
       improper conses     (and (consp x)
                                (not (true-listp x)))
       strings             (stringp x)
       characters          (characterp x)

Thus, a suitable concl to recognize the naturals would be (or (equal x
0) (and (integerp x) (> x 0))) but it turns out that we also permit
(and (integerp x) (>= x 0)).  Similarly, the true-lists could be
specified by

     (or (equal x nil) (and (consp x) (true-listp x)))

but we in fact allow (true-listp x).  When time permits we will
document more fully what is allowed or implement a macro that permits
direct specification of the desired type in terms of the primitives.

There are essentially four forms of :compound-recognizer rules, as the
third and fourth forms are equivalent, as are the fifth and sixth.  We
explain how such rules are used by considering the individual forms.

Consider a rule of the first form, (implies (fn x) concl).  The effect
of such a rule is that when the rewriter assumes (fn x) true, as it
would while diving through (if (fn x) xxx ...) to rewrite xxx, it
restricts the type of x as specified by concl.  However, when assuming
(fn x) false, as necessary in (if (fn x) ... xxx), the rule permits no
additional assumptions about the type of x.  For example, if fn is
primep, i.e., the predicate that recognizes prime numbers, then
(implies (primep x) (and (integerp x) (>= x 0))) is a compound
recognizer rule of the first form.  When (primep x) is assumed true,
the rewriter gains the additional information that x is a natural
number.  When (primep x) is assumed false, no additional information is
gained -- since x may be a non-prime natural or may not even be a
natural.

The second general form addresses itself to the symmetric case, when
assuming (fn x) false permits type restrictions on x but assuming (fn
x) true permits no such restrictions.  For example, if we defined exprp
to be the recognizer for well-formed expressions for some language in
which all symbols, numbers, character objects and strings were
well-formed -- e.g., the well-formedness rules only put restrictions on
expressions represented by consps -- then the theorem (implies (not
(exprp x)) (consp x)) is a rule of the second form.  Assuming (exprp x)
true tells us nothing about the type of x; assuming it false tells us x
is a consp.

The third and fourth general forms, which are really equivalent, address
themselves to the case where one type may be deduced from (fn x) and a
generally unrelated type may be deduced from its negation.  If we
modified the expression recognizer above so that character objects are
illegal, then rules of the third and fourth forms are

     (and (implies (exprp x) (not (characterp x)))
          (implies (not (exprp x)) (or (consp x) (characterp x)))).
     (if (exprp x)
         (not (characterp x))
       (or (consp x) (characterp x)))

Finally, rules of the fifth and sixth classes address the case where fn
recognizes all and only the objects whose type is described.  In these
cases, fn is really just a new name for some "compound recognizers."
The classic example is (booleanp x), which is just a handy combination
of two primitive types:

     (iff (booleanp x) (or (equal x t) (equal x nil))).

Often it is best to disable fn after proving that it is a compound
recognizer, since (fn x) will not be recognized as a compound
recognizer once it has been expanded.

Every time you prove a new compound recognizer rule about fn it
overrides all previously proved compound recognizer rules about fn.
Thus, if you want to establish the type implied by (fn x) and you want
to establish the type implied by (not (fn x)), you must prove a
compound recognizer rule of the third, fourth, fifth, or sixth forms.
Proving a rule of the first form followed by one of the second only
leaves the second fact in the data base.

Compound recognizer rules can be disabled with the effect that older
rules about fn, if any, are exposed.

If you prove more than one compound recognizer rule for a function, you
may see a *warning* message to the effect that the new rule is not as
"restrictive" as the old.  That is, the new rules do not give the
rewriter strictly more type information than it already had.  The new
rule is stored anyway, overriding the old, if enabled.  You may be
playing subtle games with enabling or rewriting.  But two other
interpretions are more likely, we think.  One is that you have
forgotten about an earlier rule and should merely print it out to make
sure it says what you know and then forget your new rule.  The other is
that you meant to give the system more information and the system has
simply been unable to extract the intended type information from the
term you placed in the conclusion of the new rule.  Given our lack of
specificity in saying how type information is extracted from rules, you
can hardly blame yourself for this problem.  Sorry.  If you suspect
you've been burned this way, you should rephrase the new rule in terms
of the primitive recognizing expressions above and see if the warning
is still given.  It would also be helpful to let us see your example so
we can consider it as we redesign this stuff.

Compound recognizer rules are similar to :forward-chaining rules in
that the system deduces new information from the act of assuming
something true or false.  If a compound recognizer rule were stored as
a forward chaining rule it would have essentially the same effect as
described, when it has any effect at all.  The important point is that
:forward-chaining rules, because of their more general and expensive
form, are used "at the top level" of the simplification process: we
forward chain from assumptions in the goal being proved.  But compound
recognizer rules are built in at the bottom-most level of the
simplifier, where type reasoning is done.

All that said, compound recognizer rules are a rather fancy,
specialized mechanism.  It may be more appropriate to create
:forward-chaining rules instead of :compound-recognizer rules.

CONGRUENCE    the relations to maintain while simplifying arguments

See RULE-CLASSES for a general discussion of rule classes and
how they are used to build rules from formulas.  An example :corollary
formula from which a :congruence rule might be built is:

     Example:
     (implies (set-equal x y)
              (iff (memb e x) (memb e y))).

Also see DEFCONG and see EQUIVALENCE.

     General Form:
     (implies (equiv1 xk xk-equiv)
              (equiv2 (fn x1... xk       ...xn)
                      (fn x1... xk-equiv ...xn)))

where equiv1 and equiv2 are known equivalence relations, fn is an n-ary
function symbol and the xi and xk-equiv are all distinct variables.
The effect of such a rule is to record that the equiv2-equivalence of
fn-expressions can be maintained if, while rewriting the kth argument
position, equiv1-equivalence is maintained.  See EQUIVALENCE
for a general discussion of the issues.  We say that equiv2, above, is
the "outside equivalence" in the rule and equiv1 is the "inside
equivalence for the kth argument"

The macro form (defcong equiv1 equiv2 (fn x1 ... x1) k) is an
abbreviation for a defthm of rule-class :congruence that attempts to
establish that equiv2 is maintained by maintaining equiv1 in fn's kth
argument.  The defcong macro automatically generates the general
formula shown above.  See DEFCONG.

The memb example above tells us that (memb e x) is propositionally
equivalent to (memb e y), provided x and y are set-equal.  The outside
equivalence is iff and the inside equivalence for the second argument
is set-equal.  If we see a memb expression in a propositional context,
e.g., as a literal of a clause or test of an if (but not, for example,
as an argument to cons), we can rewrite its second argument maintaining
set-equality.  For example, a rule stating the commutativity of append
(modulo set-equality) could be applied in this context.  Since equality
is a refinement of all equivalence relations, all equality rules are
always available.  See REFINEMENT.

All known :congruence rules about a given outside equivalence and fn
can be used independently.  That is, consider two :congruence rules
with the same outside equivalence, equiv, and about the same function
fn.  Suppose one says that equiv1 is the inside equivalence for the
first argument and the other says equiv2 is the inside equivalence for
the second argument.  Then (fn a b) is equiv (fn a' b') provided a is
equiv1 to a' and b is equiv2 to b'.  This is an easy consequence of the
transitivity of equiv.  It permits you to think independently about the
inside equivalences.

Furthermore, it is possible that more than one inside equivalence for a
given argument slot will maintain a given outside equivalence.  For
example, (length a) is equal to (length a') if a and a' are related
either by list-equal or by string-equal.  You may prove two (or more)
:congruence rules for the same slot of a function.  The result is that
the system uses a new, "generated" equivalence relation for that slot
with the result that rules of both (or all) kinds are available while
rewriting.

:Congruence rules can be disabled.  For example, if you have two
different inside equivalences for a given argument position and you
find that the :rewrite rules for one are unexpectedly preventing the
application of the desired rule, you can disable the rule that
introduced the unwanted inside equivalence.

More will be written about this as we develop the techniques.