20.2 The Top-Level Loop

Normally one interacts with Lisp through a “top-level read-eval-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.

[Variable] +
[Variable] ++
[Variable] +++

While a form is being evaluated by the top-level loop, the variable + is bound to the previous form read by the loop. The variable ++ holds the previous value of + (that is, the form evaluated two interactions ago), and +++ holds the previous value of ++.


[Variable] -

While a form is being evaluated by the top-level loop, the variable - is bound to the form itself; that is, it is the value about to be given to + once this interaction is done.

Notice of correction. In the first edition, the name of the variable - was inadvertently omitted.

[Variable] *
[Variable] **
[Variable] ***

While a form is being evaluated by the top-level loop, the variable * 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 +. If several values were produced, * contains the first value only; * contains nil if zero values were produced. The variable ** holds the previous value of * (that is, the result printed two interactions ago), and *** holds the previous value of **.

If the evaluation of + is aborted for some reason, then the values associated with *, **, and *** are not updated; they are updated only if the printing of values is at least begun (though not necessarily completed).


[Variable] /
[Variable] //
[Variable] ///

While a form is being evaluated by the top-level loop, the variable / 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 +. The value of * should always be the same as the car of the value of /. The variable // holds the previous value of / (that is, the results printed two interactions ago), and /// holds the previous value of //. Therefore the value of ** should always be the same as the car of //, and similarly for *** and ///.

If the evaluation of + is aborted for some reason, then the values associated with /, //, and /// are not updated; they are updated only if the printing of values is at least begun (though not necessarily completed).


As an example of the processing of these variables, consider the following possible transcript, where > is a prompt by the top-level loop for user input:

>(cons - -) ;Interaction 1
((CONS - -) CONS - -) ;Cute, huh?

>(values) ;Interaction 2
                                ;Nothing to print
>(cons ’a ’b) ;Interaction 3
(A . B) ;There is a single value

>(hairy-loop)̂G ;Interaction 4
### QUIT to top level. ;(User aborts the computation.)

>(floor 13 4) ;Interaction 5
3 ;There are two values
1

At this point we have:

+++  (cons ’a ’b) ***  NIL ///  ()
++  (hairy-loop)  **  (A . B)//  ((A . B))
+  (floor 13 4)  *  3 /  (3 1)