Contents
《On Lisp》
On Lisp, P31(3.1 Functional Design)
A destructive function is one that can alter the arguments passed to
it. However, even destructive functions usually work by returning
values: you have to assume that nreverse
will recycle lists you give
to it as arguments, but you still can't assume that ti will reverse
them. As before, the reversed list has to be found in return
value. You still can't write
in the middle of a function and assume that afterwards lst
will be
reversed. This is what happens in most implementations:
To reverse lst
, you would have to set lst
to the return value, as
with plain reverse
.
On Lisp, P36(3.4 Functional Interface)
A corollary of convention above is that functions shouldn't return
anything that isn't safe to modify. Thus one should avoid writing
functions whose return values incorporate quoted objects. If we define
exclaim
so that its return value incorporates a quoted list,
Then any later destructive modification of the return value
could alter the list within the function:
To make exclaim
proof against such proglems, it should be written:
There is one major exception to the rule that functions shouldn't return quoted lists: the functions which generate macro expansions. Macro expanders can safely incorporate quoted lists in the expansions they generate, if the expansions are going straight to the compiler.
On Lisp, P87(7.2 Backquote)
The comma causes the list (1 2 3)
to be inserted in place of b
, while
the comma-at causes the elements of the list to be inserted
there. There are some additional restrictions on the use of comma-at:
- In order for its argument to be spliced, comma-at must occur
within a sequence. It's an error to say something like
`,@b
because there is nowhere to splice the value of b. - The object to be spliced must be a list, unless it occurs
last. The expression
`(a ,@1)
will evaluate to(a . 1)
, but attempting to splice an atom into the middle of a list, as in`(a ,@1 b)
, will cause an error.
...The effect of comma-at can be achieved without using backquote. The
expression `(a ,@b c)
is equal to (cons 'a (append b (list 'c)))
, for
example. Comma-at exists only to make such expression-generating
expressions more readable.
On Lisp, P102(7.9 Dependence On Macros)
CLTL2 Says that “a macro definition must be seen by the compiler before the first use of the macro.” Implementations vary in how they respond to violations of this rule. Fortunately it's easy to avoid both types of problem. If you adhere to the following two principles, you need never worry about state or nonexistent macro definitions:
- Define macros before functions (or macros) which call them.
- When a macro is redefined, also recompile all the functions (or macros) which call it — directly or via other macors.
It has been suggested that all the macros in a program be put in a
separate file, to make it easier to ensure that macro definitions are
compiled first. That's taking things too far. It would be resonable to
put general-purpose macros like while
into a separate file, but
general-purpose utilities ought to be separated from the rest of a
program anyway, whether they're functions or macros.
Some macros are written just for use in one specific part of a program, and these should be defined with the code which uses them. So long as the definition of each macro appears before any calls to it, your programs will compile fine. Collecting together all your macros, simply because they're macros, would do nothing but make your code harder to read.
On Lisp, P129(9.7 Avoiding Capture with Gensyms)
In CLTL2 Common Lisp, the number in a gensym's printed representation
comes from *gensym-counter*
, a global variable always bound to an
integer. By resetting this counter we can cause two gensyms to print
the same
but they won't be identical.