A symbol naming the function to which the transform is to be applied.
The symbol naming the transformation -- it should be unique for the function being transformed -- and provides a handle with which to redefine an existing transform.
This must match against the form being expanded before expansion is allowed to take place, in the sense that it must be valid to call a function with such a lambda-list using the arguments supplied in the candidate-form for expansion.
The body of the expander function, the result of which replaces the original form (unless it evaluates to compiler::%pass%
, in which case no transformation is applied).
deftransform
, like defmacro
, defines a function that computes the expansion of a form. Transforms are only used by the compiler and not by the interpreter. deftransform
allows you to add to the optimizations performed by the compiler.
(compiler:deftransform + +-of-2 (x y)
'(system::|+2| ,x ,y))
(compiler:deftransform + +-of-many (x &rest y)
'(system::|+2| ,x (+ ,@y)))
;; now an expression like (+ a b c 4 5 7 d e f)
;; compiles to use the binary version
;; of + (inlined by default),
;; rather than the full (slow) version of +
(compiler:deftransform list list-of-1 (x) '(cons ,x '()))
(compiler:deftransform list list-of-2 (x y)
'(cons ,x (cons ,y '())))
;; save having to call list -
;; cons is inlined by default
(compiler:deftransform constant my-trans (x)
(cond ((constantp x) x)
((consp x) '(quote ,(eval x)))
(t 'compiler::%pass%))) ; give up if not a cons
(compile (defun three-list () (constant (list 1 2 3))))
;; the function three-list returns the
;; same list (1 2 3)
;; every time it is called...
(LIST-OF-2 LIST-OF-1 COMPILER::LIST-TRANSFORM)
as its result, since a similar transform already exists in the compiler, by the name compiler::list*-transform
.
deftransform
differs from defmacro
in various ways:
The evaluation of the body can return compiler:%pass%
indicating that the form is not to be expanded (in other words, the transform method has elected to give up trying to improve the code).
The compiler only calls the expander function if the arguments match the lambda list -- macros are unconditionally expanded.
There can be several deftransforms
for the same symbol, each having a different name. (The compiler calls each one in turn until one succeeds. This repeats until they all pass, so that the replacement form may itself be transformed.)
If a transform takes keyword arguments the compiler preserves the correct order of evaluation.
A carelessly written deftransform
may lead the compiler to transform valid Common Lisp into incorrect code -- there is no semantic checking of the transform.