-
Notifications
You must be signed in to change notification settings - Fork 9
/
eval.tex
712 lines (615 loc) · 35.5 KB
/
eval.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
%Part{Eval, Root = "CLM.MSS"}
%%%Chapter of Spice Lisp Manual. Copyright 1984, 1988, 1989 Guy L. Steele Jr.
\clearpage\def\pagestatus{FINAL PROOF}
\ifx \rulang\Undef
\chapter{Evaluator}
The mechanism that executes Lisp programs is called the evaluator.
More precisely, the evaluator accepts a form and performs the
computation specified by the form. This mechanism is made available
to the user through the function \cdf{eval}.
The evaluator is typically implemented as an interpreter
that traverses the given form recursively, performing each step
of the computation as it goes. An interpretive implementation is not
required, however. A permissible alternative approach is
for the evaluator first to completely compile the form into
machine-executable code and then invoke the resulting code.
This technique virtually eliminates incompatibilities
between interpreted and compiled code but also renders the \cdf{evalhook}
mechanism relatively useless.
Various mixed strategies are also possible. All of these approaches
should produce the same results when executing a correct program
but may produce different results for incorrect programs.
For example, the approaches may differ as to when macro calls
are expanded; macro definitions should not depend on the time
at which they are expanded. Implementors should
document the evaluation strategy for each implementation.
\section{Run-Time Evaluation of Forms}
The function \cdf{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 \cdf{evalhook} and \cdf{applyhook} provide alternative
interfaces to the evaluator mechanism for use by these debugging routines.
\begin{defun}[Function]
eval form
The \emph{form} is evaluated in the current dynamic environment and
a null lexical environment. Whatever results from the evaluation
is returned from the call to \cdf{eval}.
Note that when you write a call to \cdf{eval} \emph{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 \cdf{eval}). Then the argument
is passed to the \cdf{eval} function, where another evaluation occurs.
For example:
\begin{lisp}
(eval (list 'cdr (car '((quote (a . b)) c)))) \EV\ b
\end{lisp}
The argument form \cd{(list 'cdr (car '((quote (a . b)) c)))} is evaluated
in the usual way to produce the argument \cd{(cdr (quote (a . b)))};
this is then given to \cdf{eval} because \cdf{eval} is being called explicitly,
and \cdf{eval} evaluates its argument \cd{(cdr (quote (a . b)))} to produce \cdf{b}.
If all that is required for some application is
to obtain the current dynamic value of a given symbol, the function
\cdf{symbol-value} may be more efficient than \cdf{eval}.
\begin{new}
X3J13 voted in January 1989
\issue{MAPPING-DESTRUCTIVE-INTERACTION}
to restrict user side effects; see section~\ref{STRUCTURE-TRAVERSAL-SECTION}.
\end{new}
\end{defun}
\begin{defun}[Variable]
*evalhook* \\
*applyhook*
If the value of \cdf{*evalhook*} is not {\false}, then \cdf{eval} behaves
in a special way. The non-{\false} value of \cdf{*evalhook*} should be a function
that takes two arguments, a form and an environment;
this is called the \emph{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 \cdf{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 \cdf{*applyhook*} is similar to \cdf{*evalhook*} but is used
when a function is about to be applied to arguments.
If the value of \cdf{*applyhook*} is not {\false}, then \cdf{eval} behaves
in a special way.
\begin{new}
X3J13 voted in January 1989
\issue{APPLYHOOK-ENVIROMENT}
to revise the definition of \cdf{*applyhook*}.
Its value should be a function of \emph{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.
\end{new}
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 \cdf{eval}. It is not used for applications via \cdf{apply} or
\cdf{funcall}, for applications by such functions as \cdf{map} or
\cdf{reduce}, or for invocation of macro-expansion functions
by either \cdf{eval} or \cdf{macroexpand}.
\begin{newer}
X3J13 voted in June 1988 \issue{FUNCTION-TYPE} to specify
that the value of \cdf{*macroexpand-hook*} is first coerced to a
function before being called as the expansion interface hook.
This vote made no mention of \cdf{*evalhook*} or \cdf{*applyhook*},
but this may have been an oversight.
A proposal was submitted to X3J13 in September 1989 to specify
that the value of \cdf{*evalhook*} or \cdf{*applyhook*} is first coerced to a
function before being called. If this proposal is accepted,
the value of either variable may be \cdf{nil}, any other symbol,
a lambda-expression, or any object of type \cdf{function}.
\end{newer}
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
\cdf{evalhook}, \cdf{applyhook}, and \cdf{macroexpand}.
When either kind of hook function is invoked, both of the variables
\cdf{*evalhook*}
and \cdf{*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 \cdf{evalhook}
and \cdf{applyhook} are useful for performing recursive evaluations
and applications within the hook function.
The hook feature is provided as an aid to debugging.
The \cdf{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 \cdf{*evalhook*} and \cdf{*applyhook*} are
automatically reset to {\false} as a safety feature.
\end{defun}
\begin{defun}[Function]
evalhook form evalhookfn applyhookfn &optional env \\
applyhook function args evalhookfn applyhookfn &optional env
The functions \cdf{evalhook} and \cdf{applyhook} are provided to make it
easier to exploit the hook feature.
In the case of \cdf{evalhook}, the \emph{form} is evaluated.
In the case of \cdf{applyhook}, the \emph{function} is applied to the
list of arguments \emph{args}. In either case,
for the duration of the operation
the variable \cdf{*evalhook*} is bound to \emph{evalhookfn}, and
\cdf{*applyhook*} is bound to \emph{applyhookfn}.
Furthermore, the \emph{env} argument
is used as the lexical environment for the operation;
\emph{env} defaults to the null environment.
The check for a hook function is \emph{bypassed} for the evaluation
of the \emph{form} itself (for \cdf{evalhook}) or for the application
of the \emph{function} to the \emph{args} itself (for \cdf{applyhook}),
but not for subsidiary evaluations and applications
such as evaluations of subforms. It is this one-shot bypass that makes
\cdf{evalhook} and \cdf{applyhook} so useful.
\begin{new}
X3J13 voted in January 1989
\issue{APPLYHOOK-ENVIROMENT}
to eliminate the optional \emph{env}
parameter to \cdf{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.
\end{new}
Here is an example of a very simple tracing routine that uses just the
\cdf{evalhook} feature.
\begin{lisp}
(defvar *hooklevel* 0) \\
\\
(defun hook (x) \\
~~(let ((*evalhook* 'eval-hook-function)) \\
~~~~(eval x))) \\
\\
(defun eval-hook-function (form \cd{\&rest} env) \\
~~(let ((*hooklevel* (+ *hooklevel* 1))) \\
~~~~(format *trace-output* "{\Xtilde}\%{\Xtilde}V{\Xatsign}TForm:~~{\Xtilde}S" \\
~~~~~~~~~~~~(* *hooklevel* 2) form) \\
~~~~(let ((values (multiple-value-list \\
~~~~~~~~~~~~~~~~~~~~~(evalhook form \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\#'eval-hook-function \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{\nil} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~env)))) \\
~~~~~~(format *trace-output* "{\Xtilde}\%{\Xtilde}V{\Xatsign}TValue:{\Xtilde}{\Xlbrace} {\Xtilde}S{\Xtilde}{\Xrbrace}" \\
~~~~~~~~~~~~~~(* *hooklevel* 2) values) \\
~~~~~~(values-list values))))
\end{lisp}
Using these routines, one might see the following interaction:
\begin{lisp}
(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)
\end{lisp}
\end{defun}
\begin{defun}[Function]
constantp object
If the predicate \cdf{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 \cdf{defconstant},
such as \cdf{nil}, \cdf{t}, and \cdf{pi}.
In addition, a list whose \emph{car} is \cdf{quote},
such as \cd{(quote foo)}, is considered to be a constant.
If \cdf{constantp} is false of an object, then
that object, considered as a form,
might or might not always evaluate to the same thing.
\end{defun}
\section{The Top-Level Loop}
Normally one interacts with Lisp through a ``top-level
\cdf{read}-\cdf{eval}-\cdf{print} loop,'' so called because
it is the highest level of control and consists of an endless
loop that reads an expression, evaluates it, and prints the
results. One has an effect on the state of the Lisp system
only by invoking actions that have side effects.
The precise nature of the top-level loop for Common Lisp
is purposely not rigorously specified here so that implementors can
experiment to improve the user interface.
For example, an implementor may choose to require line-at-a-time
input, or may provide a fancy editor or complex graphics-display
interface. An implementor may choose to provide
explicit prompts for input,
or may choose (as MacLisp does) not to clutter up the transcript
with prompts.
The top-level loop is required to trap all throws and recover gracefully.
It is also required to print all values resulting from evaluation of a form,
perhaps on separate lines. If a form returns zero values, as little
as possible should be printed.
The following variables are maintained by the top-level loop
as a limited safety net, in case the user forgets to save an interesting input
expression or output value. (Note that the names of some of these variables
violate the convention that names of global variables begin and end with
an asterisk.) These are intended primarily for user interaction, which is why
they have short names. Use of these variables should be avoided in programs.
\begin{defun}[Variable]
+ \\
++ \\
+++
While a form is being evaluated by the top-level loop,
the variable \cdf{+} is bound to the previous form read by the loop.
The variable \cdf{++} holds the previous value of \cdf{+} (that is, the form
evaluated two interactions ago), and \cdf{+++} holds the previous value
of \cdf{++}.
\end{defun}
\begin{defun}[Variable]
-
While a form is being evaluated by the top-level loop,
the variable \cdf{-} is bound to the form itself; that is,
it is the value about to be given to \cdf{+} once this interaction
is done.
\begin{new}%CORR
\emph{Notice of correction.}
In the first edition, the name of the variable \cdf{-} was
inadvertently omitted.
\end{new}
\end{defun}
\begin{defun}[Variable]
* \\
** \\
***
While a form is being evaluated by the top-level loop,
the variable \cdf{*} is bound to the result printed at the
end of the last time through the loop; that is, it is the value
produced by evaluating the form in \cdf{+}. If several values were produced,
\cdf{*} contains the first value only; \cdf{*} contains {\nil} if zero values
were produced.
The variable \cdf{**} holds the previous value of \cdf{*} (that is, the result
printed two interactions ago), and \cdf{***} holds the previous value
of \cdf{**}.
If the evaluation of \cdf{+} is aborted for some reason,
then the values associated with \cdf{*}, \cdf{**}, and \cdf{***} are not updated;
they are updated only if the printing of values is at least begun (though not
necessarily completed).
\end{defun}
\begin{defun}[Variable]
/ \\
// \\
///
While a form is being evaluated by the top-level loop,
the variable \cdf{/} is bound to a list of the results printed at the
end of the last time through the loop; that is, it is a list of all values
produced by evaluating the form in \cdf{+}. The value of \cdf{*} should
always be the same as the \emph{car} of the value of \cdf{/}.
The variable \cdf{//} holds the previous value of \cdf{/} (that is, the results
printed two interactions ago), and \cdf{///} holds the previous value
of \cdf{//}. Therefore the value of \cdf{**} should always be the same
as the \emph{car} of \cdf{//}, and similarly for \cdf{***} and \cdf{///}.
If the evaluation of \cdf{+} is aborted for some reason,
then the values associated with \cdf{/}, \cdf{//}, and \cdf{///} are not updated;
they are updated only if the printing of values is at least begun (though not
necessarily completed).
\end{defun}
As an example of the processing of these variables, consider the
following possible transcript, where \cdf{>} is a prompt by
the top-level loop for user input:
\begin{lisp}
\hskip 12pc\=\kill
>(cons - -)\>;\textrm{Interaction 1} \\
((CONS - -) CONS - -)\>;\textrm{Cute, huh?} \\
\\
>(values)\>;\textrm{Interaction 2} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Nothing to print} \\
>(cons 'a 'b)\>;\textrm{Interaction 3} \\
(A . B)\>;\textrm{There is a single value} \\
\\
>(hairy-loop){\Xcircumflex}G\>;\textrm{Interaction 4} \\
\#\#\# QUIT to top level.\>;\textrm{(User aborts the computation.)} \\
\\
>(floor 13 4)\>;\textrm{Interaction 5} \\
3\>;\textrm{There are two values} \\
1
\end{lisp}
At this point we have:
\begin{lisp}
\begin{tabular*}{\textwidth}{@{}l@{\extracolsep{\fill}}ll@{}}
+++ \EV\ (cons 'a 'b)&*** \EV\ NIL &/// \EV\ () \\
++ \EV\ (hairy-loop)&** \EV\ (A . B)&// \EV\ ((A . B)) \\
+ \EV\ (floor 13 4)&* \EV\ 3 &/ \EV\ (3 1)
\end{tabular*}
\end{lisp}
%RUSSIAN
\else
\chapter{Вычислитель}
Механизм, который выполняет программы на Лиспе, называется вычислитель. Более
подробно, вычислитель принимает форму и выполняет расчёты определённые
формой. Этот механизм доступен пользователю через функцию \cdf{eval}.
Вычислитель, как правило, реализован как интерпретатор, который рекурсивно
проходит по данной форме, выполняя каждый шаг вычисления по мере
прохода. Однако, интерпретирующая реализация не обязательна. Допустимым
альтернативным подходом для вычислителя является вначале полностью
скомпилировать форму в выполняемый машиной код, и затем вызывать результат. Эта
техника практически исключает несовместимости между интерпретируемым и
компилируемым кодом, но также делает механизм \cdf{evalhook} относительно
бесполезным. Допустимы также различные смешанные стратегии. Все эти подходы
должны обеспечивать одинаковые результаты при выполнении корректной программы,
но могут возвращать различные результаты для неправильных программ. Например,
поведение может отличаться в том, когда раскрывается вызов макроса, определения
макросов не должны зависеть от времени, когда они раскрываются. Разработчики
должны документировать стратегию вычисления для каждой реализации.
\section{Вычисление форм}
Функция \cdf{eval} является главным пользовательским интерфейсом к вычислителю.
Для пользовательских отладочных функций в интерпретаторе предусмотрены ловушки.
Функции \cdf{evalhook} и \cdf{applyhook} предоставляют альтернативные интерфейсы
к механизму вычислителя для использования этих отладочных возможностей.
\begin{defun}[Функция]
eval form
Форма \emph{form} вычисляется в текущем динамическом окружении и нулевом
лексическом. Что бы ни было вычислено, данное значение возвращается в качестве
результата \cdf{eval}.
Следует отметить, что когда вы записываете вызов к \cdf{eval}, то для переданной
формы происходят \emph{два} уровня вычислений.
Сначала происходит вычисление формы аргумента, как и любого аргумента для любой
функции. Данное вычисление в свою очередь неявно вызывает \cdf{eval}.
Затем происходит вычисление значения аргумента переданного в функцию \cdf{eval}.
Например:
\begin{lisp}
(eval (list 'cdr (car '((quote (a . b)) c)))) \EV\ b
\end{lisp}
Форма аргумента \cd{(list 'cdr (car '((quote (a . b)) c)))} вычисляется в
\cd{(cdr (quote (a . b)))}.
Затем \cdf{eval} вычисляет полученный аргумент и возвращает \cd{b}.
Если всё, что требуется - это получить текущее динамическое значение для данного
символа, то функция \cdf{symbol-value} может оказаться более эффективной, чем
\cdf{eval}.
Пользователь ограничен в создании побочных действий так, как это описано в
разделе~\ref{STRUCTURE-TRAVERSAL-SECTION}
\end{defun}
\begin{defun}[Переменная]
*evalhook* \\
*applyhook*
Если значение \cdf{*evalhook*} не является {\false}, тогда \cdf{eval} ведёт себя
специальным образом. Не-{/false} значение \cdf{*evalhook*} должно быть функцией,
которая принимает два аргумента, форму и окружение.
Эта функция называется <<функцией-ловушкой для вычислителя>>.
Когда форма должна быть вычислена (любая, даже просто число или символ) неявно или явно с
помощью \cdf{eval}, то вместо вычисления вызывается данная функция с формой в
первом аргументе.
Тогда функция-ловушка несёт ответственность за вычисление формы, и все что она
вернёт будет расценено как результат вычисления этой формы.
Переменная \cdf{*applyhook*} похожа на \cdf{*evalhook*}, но используется, когда
функция должна быть применена к аргументам.
Если значение \cdf{*applyhook*} не {\false}, тогда \cdf{eval} ведёт себя
специальным образом.
\begin{new}
X3J13 voted in January 1989
\issue{APPLYHOOK-ENVIROMENT}
to revise the definition of \cdf{*applyhook*}.
Its value should be a function of \emph{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.
\end{new}
Когда функция должна примениться к списку аргументов, то вызывается
функция-ловушка с данной функцией и списком аргументов в качестве параметров.
Выполнение формы доверяется функции-ловушке. То, что она вернёт, будет расценено
как результат вычисления формы.
Функция-ловушка используется для применения обычных функций внутри
\cdf{eval}. Она не используется для вызовов \cdf{apply} или
\cdf{funcall}, таких функций, как \cdf{map} или \cdf{reduce}, или
вызовов функций раскрытия макросов, таких как \cdf{eval} или \cdf{macroexpand}.
\begin{newer}
X3J13 voted in June 1988 \issue{FUNCTION-TYPE} to specify
that the value of \cdf{*macroexpand-hook*} is first coerced to a
function before being called as the expansion interface hook.
This vote made no mention of \cdf{*evalhook*} or \cdf{*applyhook*},
but this may have been an oversight.
A proposal was submitted to X3J13 in September 1989 to specify
that the value of \cdf{*evalhook*} or \cdf{*applyhook*} is first coerced to a
function before being called. If this proposal is accepted,
the value of either variable may be \cdf{nil}, any other symbol,
a lambda-expression, or any object of type \cdf{function}.
\end{newer}
Последний аргумент помещаемый в функции-ловушки содержит информацию о
лексическом окружении в формате, который зависит от реализации.
Эти аргументы одинаковы для функций \cdf{evalhook}, \cdf{applyhook} и
\cdf{macroexpand}.
Когда вызывается одна из функций-ловушек, то обе переменные \cdf{*evalhook*} и
\cdf{*applyhook} связываются со значениями {\nil} на время выполнения данных
функций. Это сделано для того, чтобы функция-ловушка не зациклилась.
Функции \cdf{evalhook} и \cdf{applyhook} полезны для выполнения рекурсивных
вычислений и применений (функции) с функцией ловушкой.
Функциональность ловушки предоставляется для облегчения отладки.
Функциональность \cdf{step} реализована с помощью такой ловушки.
Если случается нелокальный выход на верхний уровень Lisp'а, возможно потому, что
ошибка не может быть исправлена, тогда \cdf{*evalhook*} и \cdf{*applyhook*}
в целях безопасности автоматически сбрасываются в {\false}.
\end{defun}
\begin{defun}[Функция]
evalhook form evalhookfn applyhookfn &optional env \\
applyhook function args evalhookfn applyhookfn &optional env
Функции \cdf{evalhook} и \cdf{applyhook} представлены для облегчения
использования функциональности ловушек.
В случае \cdf{evalhook} вычисляется форма \emph{form}.
В случае \cdf{applyhook} функция \emph{function} применяется к списку аргументов
\emph{args}.
В обоих случаях, в процессе выполнения операции переменная \cdf{*evalhook*}
связана с \emph{evalhookfn}, и \cdf{*applyhook*} с \emph{applyhookfn}.
Кроме того, аргумент \emph{env} используется для установки лексического
окружения.
По-умолчанию \emph{env} установлен в нулевое окружение.
The check for a hook function is \emph{bypassed} for the evaluation
of the \emph{form} itself (for \cdf{evalhook}) or for the application
of the \emph{function} to the \emph{args} itself (for \cdf{applyhook}),
but not for subsidiary evaluations and applications
such as evaluations of subforms. It is this one-shot bypass that makes
\cdf{evalhook} and \cdf{applyhook} so useful. FIXME
\begin{new}
X3J13 voted in January 1989
\issue{APPLYHOOK-ENVIROMENT}
to eliminate the optional \emph{env}
parameter to \cdf{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.
\end{new}
Вот пример, очень простой функции трассировки, которая использует возможности
\cdf{evalhook}.
\begin{lisp}
(defvar *hooklevel* 0) \\
\\
(defun hook (x) \\
~~(let ((*evalhook* 'eval-hook-function)) \\
~~~~(eval x))) \\
\\
(defun eval-hook-function (form \cd{\&rest} env) \\
~~(let ((*hooklevel* (+ *hooklevel* 1))) \\
~~~~(format *trace-output* "{\Xtilde}\%{\Xtilde}V{\Xatsign}TForm:~~{\Xtilde}S" \\
~~~~~~~~~~~~(* *hooklevel* 2) form) \\
~~~~(let ((values (multiple-value-list \\
~~~~~~~~~~~~~~~~~~~~~(evalhook form \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\#'eval-hook-function \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{\nil} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~env)))) \\
~~~~~~(format *trace-output* "{\Xtilde}\%{\Xtilde}V{\Xatsign}TValue:{\Xtilde}{\Xlbrace} {\Xtilde}S{\Xtilde}{\Xrbrace}" \\
~~~~~~~~~~~~~~(* *hooklevel* 2) values) \\
~~~~~~(values-list values))))
\end{lisp}
Используя эти функции можно, например, увидеть такую последовательность:
\begin{lisp}
(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)
\end{lisp}
\end{defun}
\begin{defun}[Функция]
constantp object
Если предикат \cdf{constantp} для объекта \emph{object} истинен, то данный
объект, когда рассматривается как вычисляемая форма, всегда вычисляется в одно и
то же значение.
Константные объекты включают самовычисляемые объекты, такие как числа, строковые
символы, строки, битовые вектора, ключевые символы, а также символы констант,
определённых с помощью \cdf{defconstant}, \cdf{nil}, \cdf{t} и \cdf{pi}.
В дополнение, список, у которого \emph{car} элемент равен \cdf{quote}, например
\cd{(quote foo)}, также является константным объектом.
Если \cdf{constantp} для объекта \emph{object} ложен, то этот объект,
рассматриваемый как форма, может не всегда вычисляться в одно и то же
значение.
\end{defun}
\section{Цикл взаимодействия с пользователем}
С Lisp'ом можно работать через специальный цикл вида
<<\cdf{read}-\cdf{eval}-\cdf{print} и сначала>>.
Изменять состояние Lisp системы можно вызовом в этом цикле действий, имеющих
побочные эффекты.
Точное определение такого цикла для Common Lisp'а не указывается здесь
специально, оставляя разработчикам поле для творчества.
Например, они могут сделать командную строку, или простой текстовый редактор,
или сложный графический интерфейс. Разработчики могут предоставлять явный запрос
ввода, или (как в MacLisp'е) не загромождать экран подсказками.
Цикл взаимодействия с пользователем должен ловить все исключения и изящно их
обрабатывать. Он должен также выводить все результаты вычисления форм, возможно
в отдельных строках. Если форма вернула ноль значений, это также должно быть
отображено.
Для удобства работы, например в случае, если пользователь забыл сохранить
интересное введённое выражение или выведенное значение
Следующие переменные управляются циклом взаимодействия с пользователем,. (Следует отметить, что
имена некоторых этих переменных нарушают нотацию глобальных переменных в
использовании звёздочек в начале и конце имени.) Эти переменные в основном
используются для взаимодействия с пользователем, поэтому имеют короткие
имена. Использование этих переменных в программах следует избегать.
\begin{defun}[Переменная]
+ \\
++ \\
+++
Когда форма вычисляется в цикле взаимодействия, переменная \cdf{+} связывается с
предыдущим прочитанным выражением.
Переменная \cdf{++} хранит предыдущее относительно значения \cdf{+} (то есть,
форма вычисленная два шага назад), и \cdf{+++} хранит предыдущее значение
относительно \cdf{++}.
\end{defun}
\begin{defun}[Переменная]
-
Когда формы выполняется в цикле взаимодействия, переменная \cdf{-} связана с
этой формой. Это значение, которое получит переменная \cdf{+} на следующей
итерации цикла.
\end{defun}
\begin{defun}[Переменная]
* \\
** \\
***
Во время вычисления формы в цикле взаимодействия, переменная \cdf{*} связана с
результатом выполнения предыдущей формы, то есть значения формы, которая
хранится в \cdf{+}.
Если результат той формы содержал несколько значений, в \cdf{*} будет только
первое. Если было возвращено ноль значений, \cdf{*} будет содержать {\nil}.
Переменная \cdf{**} хранит предыдущее значение относительно \cdf{*}. То есть,
результат вычисления формы из \cdf{**}. \cdf{***} хранит предыдущее значение
относительно \cdf{***}.
Если выполнение \cdf{+} было по каким-то причинам прервано, тогда значения
\cdf{*}, \cdf{**} и \cdf{***} не меняются.
Они изменяются, если вывод значений как минимум начался (необязательно, чтобы он
закончился).
\end{defun}
\begin{defun}[Переменная]
/ \\
// \\
///
Во время вычисления формы в цикле взаимодействия,
переменная \cdf{/} связана со списком результатов выведенных на предыдущей
итерации. То есть это список всех значений выполнения формы \cdf{+}.
Значение \cdf{*} должно всегда совпадать со значением \emph{car} элемента
значения \cdf{/}.
Переменная \cdf{//} хранит предыдущий список значений относительно \cdf{/} (то
есть, результат вычисленный две итерации назад), и \cdf{///} содержит предыдущий
список значений относительно \cdf{///}. Таким образом, значение \cdf{**} должно
всегда совпадать со значением \emph{car} элемента списка \cdf{//}, а \cdf{***} с
с \emph{car} элементом \cdf{///}.
Если выполнение \cdf{+} было по каким-то причинам прервано, тогда значения
\cdf{/}, \cdf{//} и \cdf{///} не меняются.
Они изменяются, если вывод значений как минимум начался (необязательно, чтобы он
закончился).
\end{defun}
В качестве примера работы с этими переменным, рассмотрим следующую возможную
работу с системой, где \cdf{>} приглашение ввода:
\begin{lisp}
\hskip 12pc\=\kill
>(cons - -)\>;\textrm{Итерация 1} \\
((CONS - -) CONS - -)\>;\textrm{Очаровашка?} \\
\\
>(values)\>;\textrm{Итерация 2} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Ничего не выводится} \\
>(cons 'a 'b)\>;\textrm{Итерация 3} \\
(A . B)\>;\textrm{Это одно значение} \\
\\
>(hairy-loop){\Xcircumflex}G\>;\textrm{Итерация 4} \\
\#\#\# QUIT to top level.\>;\textrm{(Пользователь прервал вычисления.)} \\
\\
>(floor 13 4)\>;\textrm{Итерация 5} \\
3\>;\textrm{Вернулось два значения} \\
1
\end{lisp}
В этой точке мы имеем:
\begin{lisp}
\begin{tabular*}{\textwidth}{@{}l@{\extracolsep{\fill}}ll@{}}
+++ \EV\ (cons 'a 'b)&*** \EV\ NIL &/// \EV\ () \\
++ \EV\ (hairy-loop)&** \EV\ (A . B)&// \EV\ ((A . B)) \\
+ \EV\ (floor 13 4)&* \EV\ 3 &/ \EV\ (3 1)
\end{tabular*}
\end{lisp}
\fi