Common Lisp the Language, 2nd Edition
Next: The Top-Level Loop
Up: The Evaluator
Previous: The Evaluator
The function eval
is the main user interface to the
evaluator. Hooks are provided for user-supplied debugging routines to
obtain control during the execution of an interpretive evaluator. The
functions evalhook
and applyhook
provide
alternative interfaces to the evaluator mechanism for use by these
debugging routines.
[Function]
eval
form
The form is evaluated in the current dynamic environment and
a null lexical environment. Whatever results from the evaluation is
returned from the call to eval
.
Note that when you write a call to eval
two
levels of evaluation occur on the argument form you write. First the
argument form is evaluated, as for arguments to any function, by the
usual argument evaluation mechanism (which involves an implicit use of
eval
). Then the argument is passed to the eval
function, where another evaluation occurs. For example:
(eval (list 'cdr (car '((quote (a . b)) c)))) => b
The argument form (list 'cdr (car '((quote (a . b)) c)))
is evaluated in the usual way to produce the argument
(cdr (quote (a . b)))
; this is then given to
eval
because eval
is being called explicitly,
and eval
evaluates its argument
(cdr (quote (a . b)))
to produce b
.
If all that is required for some application is to obtain the current
dynamic value of a given symbol, the function symbol-value
may be more efficient than eval
.
X3J13 voted in January 1989 (MAPPING-DESTRUCTIVE-INTERACTION) to
restrict user side effects; see section 7.9.
[Variable]
*evalhook*
*applyhook*
If the value of *evalhook*
is not nil
, then
eval
behaves in a special way. The non-nil
value of *evalhook*
should be a function that takes two
arguments, a form and an environment; this is called the eval hook
function. When a form is to be evaluated (any form at all, even a
number or a symbol), whether implicitly or via an explicit call to
eval
, no attempt is made to evaluate the form. Instead, the
hook function is invoked and is passed the form to be evaluated as its
first argument. The hook function is then responsible for evaluating the
form; whatever is returned by the hook function is assumed to be the
result of evaluating the form.
The variable *applyhook*
is similar to
*evalhook*
but is used when a function is about to be
applied to arguments. If the value of *applyhook*
is not
nil
, then eval
behaves in a special way.
The non-nil
value of *applyhook*
should be a
function that takes three arguments: a function, a list of arguments,
and an environment; this is called the apply hook
function.
X3J13 voted in January 1989 (APPLYHOOK-ENVIROMENT) to revise the
definition of *applyhook*
. Its value should be a function
of two arguments, a function and a list of arguments; no
environment information is passed to an apply hook function.
This was simply a flaw in the first edition. Sorry about that.
When a function is about to be applied to a list of arguments, no
attempt is made to apply the function. Instead, the hook function is
invoked and is passed the function and the list of arguments as its
first and second arguments. The hook function is then responsible for
evaluating the form; whatever is returned by the hook function is
assumed to be the result of evaluating the form. The apply hook function
is used only for application of ordinary functions within
eval
. It is not used for applications via
apply
or funcall
, for applications by such
functions as map
or reduce
, or for invocation
of macro-expansion functions by either eval
or
macroexpand
.
X3J13 voted in June 1988 (FUNCTION-TYPE) to specify that the value of
*macroexpand-hook*
is first coerced to a function before
being called as the expansion interface hook. This vote made no mention
of *evalhook*
or *applyhook*
, but this may
have been an oversight.
A proposal was submitted to X3J13 in September 1989 to specify that
the value of *evalhook*
or *applyhook*
is
first coerced to a function before being called. If this proposal is
accepted, the value of either variable may be nil
, any
other symbol, a lambda-expression, or any object of type
function
.
The last argument passed to either kind of hook function contains
information about the lexical environment in an implementation-dependent
format. These arguments are suitable for the functions
evalhook
, applyhook
, and
macroexpand
.
When either kind of hook function is invoked, both of the variables
*evalhook*
and *applyhook*
are rebound to the
value nil
around the invocation of the hook function. This
is so that the hook function will not be invoked recursively on
evaluations and applications that occur in the course of executing the
code of the hook function. The functions evalhook
and
applyhook
are useful for performing recursive evaluations
and applications within the hook function.
The hook feature is provided as an aid to debugging. The
step
facility is implemented using this hook.
If a non-local exit causes a throw back to the top level of Lisp,
perhaps because an error could not be corrected, then
*evalhook*
and *applyhook*
are automatically
reset to nil
as a safety feature.
[Function]
evalhook form evalhookfn applyhookfn &optional env
applyhook function args evalhookfn applyhookfn &optional env
The functions evalhook
and applyhook
are
provided to make it easier to exploit the hook feature.
In the case of evalhook
, the form is evaluated.
In the case of applyhook
, the function is applied
to the list of arguments args. In either case, for the duration
of the operation the variable *evalhook*
is bound to
evalhookfn, and *applyhook*
is bound to
applyhookfn. Furthermore, the env argument is used as
the lexical environment for the operation; env defaults to the
null environment. The check for a hook function is bypassed for
the evaluation of the form itself (for evalhook
)
or for the application of the function to the args
itself (for applyhook
), but not for subsidiary evaluations
and applications such as evaluations of subforms. It is this one-shot
bypass that makes evalhook
and applyhook
so
useful.
X3J13 voted in January 1989 (APPLYHOOK-ENVIROMENT) to eliminate the
optional env parameter to applyhook
, because it is
not (and cannot) be useful. Any function that can be applied carries its
own environment and does not need another environment to be specified
separately. This was a flaw in the first edition.
Here is an example of a very simple tracing routine that uses just
the evalhook
feature.
(defvar *hooklevel* 0)
(defun hook (x)
(let ((*evalhook* 'eval-hook-function))
(eval x)))
(defun eval-hook-function (form &rest env)
(let ((*hooklevel* (+ *hooklevel* 1)))
(format *trace-output* "~%~V@TForm: ~S"
(* *hooklevel* 2) form)
(let ((values (multiple-value-list
(evalhook form
#'eval-hook-function
nil
env))))
(format *trace-output* "~%~V@TValue:~{ ~S~}"
(* *hooklevel* 2) values)
(values-list values))))
Using these routines, one might see the following interaction:
(hook '(cons (floor *print-base* 2) 'b))
Form: (CONS (FLOOR *PRINT-BASE* 2) (QUOTE B))
Form: (FLOOR *PRINT-BASE* 3)
Form: *PRINT-BASE*
Value: 10
Form: 3
Value: 3
Value: 3 1
Form: (QUOTE B)
Value: B
Value: (3 . B)
(3 . B)
[Function]
constantp
object
If the predicate constantp
is true of an object, then
that object, when considered as a form to be evaluated, always evaluates
to the same thing; it is a constant. This includes self-evaluating
objects such as numbers, characters, strings, bit-vectors, and keywords,
as well as all constant symbols declared by defconstant
,
such as nil
, t
, and pi
. In
addition, a list whose car is quote
, such as
(quote foo)
, is considered to be a constant.
If constantp
is false of an object, then that object,
considered as a form, might or might not always evaluate to the same
thing.
Next: The Top-Level Loop
Up: The Evaluator
Previous: The Evaluator
AI.Repository@cs.cmu.edu