Major Section: EVENTS
Examples: (defun app (x y) (if (consp x) (cons (car x) (app (cdr x) y)) y)) (defun fact (n) (declare (xargs :guard (and (integerp n) (>= n 0)))) (if (zp n) 1 (* n (fact (1- n))))) General Form: (defun fn (var1 ... varn) doc-string dcl ... dcl body),where
fnis the symbol you wish to define and is a new symbolic name (see name),
(var1 ... varn)is its list of formal parameters (see name), and
bodyis its body. The definitional axiom is logically admissible provided certain restrictions are met. These are sketched below.
Note that ACL2 does not support the use of
lambda-list keywords (such as
&optional) in the formals list of functions. We do support some such
keywords in macros and often you can achieve the desired syntax by defining a
macro in addition to the general version of your function. See defmacro.
The documentation string,
doc-string, is optional; for a
description of its form, see doc-string.
The declarations (see declare),
dcl, are also optional. If more
dcl form appears, they are effectively grouped together as one.
Perhaps the most commonly used ACL2 specific declaration is of the form
(declare (xargs :guard g :measure m)). This declaration in the
of some function
fn has the effect of making the ``guard'' for
fn be the term
g and the ``measure'' be the term
m. The notion
of ``measure'' is crucial to ACL2's definitional principle. The notion of
``guard'' is not, and is discussed elsewhere; see verify-guards and
see set-verify-guards-eagerness. Note that the
:measure is ignored in
program mode; see defun-mode.
We now briefly discuss the ACL2 definitional principle, using the following definition form which is offered as a more or less generic example.
(defun fn (x y) (declare (xargs :guard (g x y) :measure (m x y))) (if (test x y) (stop x y) (step (fn (d x) y))))Note that in our generic example,
fnhas just two arguments,
y, the guard and measure terms involve both of them, and the body is a simple case split on
(test x y)leading to a ``non-recursive'' branch,
(stop x y), and a ``recursive'' branch. In the recursive branch,
fnis called after ``decrementing''
(d x)and some step function is applied to the result. Of course, this generic example is quite specific in form but is intended to illustrate the more general case.
Provided this definition is admissible under the logic, as outlined below, it adds the following axiom to the logic.
Defining Axiom: (fn x y) = (if (test x y) (stop x y) (step (fn (d x) y)))Note that the guard of
fnhas no bearing on this logical axiom.
This defining axiom is actually implemented in the ACL2 system by a
definition rule, namely
(equal (fn x y) (if (test a b) (stop a b) (step (fn (d a) b)))).See definition for a discussion of how definition rules are applied. Roughly speaking, the rule causes certain instances of
(fn x y)to be replaced by the corresponding instances of the body above. This is called ``opening up''
(fn x y). The instances of
(fn x y)opened are chosen primarily by heuristics which determine that the recursive calls of
fnin the opened body (after simplification) are more desirable than the unopened call of
This discussion has assumed that the definition of
fn was admissible.
Exactly what does that mean? First,
fn must be a previously
unaxiomatized function symbol (however, see ld-redefinition-action).
Second, the formal parameters must be distinct variable names. Third, the
guard, measure, and body should all be terms and should mention no free
variables except the formal parameters. Thus, for example, body may not
contain references to ``global'' or ``special'' variables; ACL2 constants or
additional formals should be used instead.
The final conditions on admissibility concern the termination of the
recursion. Roughly put, all applications of
fn must terminate. In
particular, there must exist a binary relation,
rel, and some unary
mp such that
rel is well-founded on objects satisfying
mp, the measure term
m must always produce something satisfying
mp, and the measure term must decrease according to
rel in each
recursive call, under the hypothesis that all the tests governing the call
are satisfied. By the meaning of well-foundedness, we know there are no
infinitely descending chains of successively
Thus, the recursion must terminate.
The only primitive well-founded relation in ACL2 is
o< (see o<), which
is known to be well-founded on the
o-ps (see o-p). For the proof of
well-foundedness, see proof-of-well-foundedness. However it is possible to
add new well-founded relations. For details, see well-founded-relation. We
discuss later how to specify which well-founded relation is selected by
defun and in the present discussion we assume, without loss of
generality, that it is
o< on the
For example, for our generic definition of
fn above, with measure term
(m x y), two theorems must be proved. The first establishes that
produces an ordinal:
(o-p (m x y)).The second shows that
mdecreases in the (only) recursive call of
(implies (not (test x y)) (o< (m (d x) y) (m x y))).Observe that in the latter formula we must show that the ``
yis ``smaller than'' the
y, provided the test,
(test x y), in the body fails, thus leading to the recursive call
(fn (d x) y).
See o< for a discussion of this notion of ``smaller than.'' It should be
noted that the most commonly used ordinals are the natural numbers and that
on natural numbers,
o< is just the familiar ``less than'' relation
<). Thus, it is very common to use a measure
m that returns a
nonnegative integer, for then
(o-p (m x y)) becomes a simple conjecture
about the type of
m and the second formula above becomes a conjecture
about the less-than relationship of nonnegative integer arithmetic.
The most commonly used measure function is
acl2-count, which computes a
nonnegative integer size for all ACL2 objects. See acl2-count.
Probably the most common recursive scheme in Lisp programming is when
some formal is supposed to be a list and in the recursive call it is replaced
cdr. For example,
(test x y) might be simply
(d x) might be
(cdr x). In that case,
(acl2-count x) is a
suitable measure because the
acl2-count of a
cons is strictly
larger than the
acl2-counts of its
car'' and ``recursion by
cdr'' are trivially
acl2-count is used as the measure and the definition
protects every recursive call by a test insuring that the decremented
argument is a
consp. Similarly, ``recursion by
1-'' in which a
positive integer formal is decremented by one in recursion, is also trivially
admissible. See built-in-clause to extend the class of trivially admissible
We now turn to the question of which well-founded relation
It should first be observed that
defun must actually select both a
o<) and a domain predicate (e.g.,
o-p) on which
that relation is known to be well-founded. But, as noted elsewhere
(see well-founded-relation), every known well-founded relation has a unique
domain predicate associated with it and so it suffices to identify simply the
xargs field of a
declare permits the explicit specification
of any known well-founded relation with the keyword
well-founded-relation. An example is given below. If the
xargs for a
defun specifies a well-founded relation, that relation
and its associated domain predicate are used in generating the termination
conditions for the definition.
well-founded-relation is specified,
defun uses the
well-founded-relation specified in the
See set-well-founded-relation to see how to set the default well-founded
relation (and, implicitly, its domain predicate). The initial default
well-founded relation is
o< (with domain predicate
This completes the brief sketch of the ACL2 definitional principle. Optionally, see ruler-extenders for a more detailed discussion of the termination analysis and resulting proof obligations for admissibility, as well as a discussion of the relation to how ACL2 stores induction schemes.
On very rare occasions ACL2 will seem to "hang" when processing a
definition, especially if there are many subexpressions of the body whose
function symbol is
if (or which macroexpand to such an expression). In
those cases you may wish to supply the following to
:normalize nil. This is an advanced feature that turns off ACL2's usual
propagation upward of
The following example illustrates all of the available declarations and most hint keywords, but is completely nonsensical. For documentation, see xargs and see hints.
(defun example (x y z a b c i j) (declare (ignore a b c) (type integer i j) (xargs :guard (symbolp x) :measure (- i j) :ruler-extenders :basic :well-founded-relation my-wfr :hints (("Goal" :do-not-induct t :do-not '(generalize fertilize) :expand ((assoc x a) (member y z)) :restrict ((<-trans ((x x) (y (foo x))))) :hands-off (length binary-append) :in-theory (set-difference-theories (current-theory :here) '(assoc)) :induct (and (nth n a) (nth n b)) :use ((:instance assoc-of-append (x a) (y b) (z c)) (:functional-instance (:instance p-f (x a) (y b)) (p consp) (f assoc))))) :guard-hints (("Subgoal *1/3'" :use ((:instance assoc-of-append (x a) (y b) (z c))))) :mode :logic :normalize nil :verify-guards nil :non-executable t :otf-flg t)) (example-body x y z i j))