Chapter 14
The Built-In Macros and Special Definitions
Local Declarations
Local declarations are used to create bindings or install handlers that are active for the remainder of the innermost body containing the declaration. Bindings created by local declarations can be referenced only in the remaining program text of the body. Handlers installed are active while the execution of the remainder of the body is active, which includes the time during which any functions called from the remainder of the body are active.
Macro |
Description |
Page |
---|---|---|
|
Creates and initializes new local bindings within the smallest enclosing implicit body. |
|
|
||
|
let
[Local Declaration]
Creates and initializes new local bindings within the smallest enclosing implicit body.
- Macro Call:
let
variables=
init;
- Arguments:
-
- variables
-
variablebnf |
(
variable-listbnf)
- init
expressionbnf
- Description:
-
let
creates local bindings for the variables, and initializes them to the values returned by init. The bindings are visible for the remainder of the smallest enclosing implicit body.The first value returned by the init is bound to the first variable, the second value to the second variable, etc. The last variable may be preceded by
#rest
, in which case it is bound to a sequence containing all the remaining values.Each variable is a variable-name or a variable-name followed by a specializer.
If more than one binding is defined, the variables are enclosed in parentheses and separated by commas.
let start = 0; let (whole-part, remainder) = truncate(amount); let (first-value, #rest rest-values) = get-initial-values();
Local variables may be specialized. This ensures that their value will always be of a given type. An attempt to initialize or assign the variable to a value not of that type will signal an error of type
<type-error>
.let elapsed-time :: <integer> = 0; let the-front-window :: <window> = front-window(); let (whole-part :: <integer>, remainder :: <real>) = truncate(amount);
local
[Local Declaration]
Creates new local bindings within the smallest enclosing implicit body and initializes them to local methods that can be self-recursive and mutually recursive.
- Macro Call:
local
{ [method
] name parameter-list [ body ]end
[method
] [ name ] },
+- Arguments:
-
- name
variable-namebnf
- parameter-list
parameter-listbnf
- body
bodybnf
- Description:
-
local
creates local methods that may be mutually recursive and self-recursive.Each name creates a new local binding. The binding is initialized to a new method specified by the parameter-list and body. In addition to being visible for the remainder of the smallest enclosing implicit body, the bindings created for the names are visible to the parameter-lists and bodies of all the methods created by the
local
declaration.The parameter-list is a standard method parameter list. A complete description of parameter lists is given in
Parameter Lists
on page 84.The body is an implicit body.
let handler
[Local Declaration]
Establishes a condition handler for the duration of the execution of smallest enclosing implicit body.
- Macro Call:
let handler
condition=
handler- Arguments:
-
- condition
type |
(
type {,
option }*)
- type
expressionbnf
- option
test-option | init-option
- test-option
test:
expressionbnf- init-option
init-arguments:
expressionbnf- handler
expressionbnf
- Description:
-
let handler
establishes a new condition handler that is in effect for the duration of the execution of the remainder of the smallest enclosing implicit body. Unlike the local declarationslet
andlocal
,let handler
does not create any bindings.- The condition describes the conditions for which the handler is
applicable.
- The type is the type of the applicable conditions. The handler will be applicable to conditions that are general instances of type.
- The test-option is a function that is called to further test the
applicability of the handler. When a condition of type type is
signaled, the test function will be called with that condition as an argument. If
the test returns true, the handler is considered applicable to the condition. If
the test returns false, the handler is considered to be inapplicable to the
condition. The default value of this option is a function that always returns
true. There can be at most one test-option.
An example use for this feature is a restart handler for restarting only from a particular condition object, for example restarting from an unbound-slot error by setting the slot and retrying the invocation of the accessor. The<set-and-continue>
restart condition will have the signaled<unbound-slot>
condition in a slot, and the handler's test will check for it. (These class names are invented for this example and are not part of the specification.) - The init-option is a sequence of alternating keywords and objects
that can be used as initialization arguments to construct a condition to which the
handler is applicable. For example, if the handler is a restart handler, a program
could retrieve the init-option by calling
do-handlers
, and could then use them to construct a corresponding restart. There can be at most one init-option. init-option defaults to an empty sequence.
- The handler is a function called to handle a condition that
matches type and passes test-option. The function should accept
two arguments. The first argument will be the condition being signaled, and the second
argument will be a next-handler function. The handler handles the condition by taking
a nonlocal exit, returning values according to the condition's recovery protocol, or
tail-recursively calling
signal
of a restart. The function can decline to handle the condition by tail-recursively calling the next-handler function with no arguments.
test-option and handler are distinct so that handler applicability can be tested without actually handling (which might take a nonlocal exit). One use for this is constructing a list of available restart handlers.
There is no
condition wall,
i.e., when executing handler the set of available handlers is not reset to the handlers that were in effect when thelet handler
was entered.Implementations are encouraged to implement
let handler
in a way that optimizes establishing a handler for both speed and space, even if that increases the cost of signaling. The assumption is that most of the time a handler will never be used, because the exception it is looking for will never occur.type, handler, test-option, and init-option are executed before execution of the rest of the enclosing body begins.
- The condition describes the conditions for which the handler is
applicable.