Common Lisp the Language, 2nd Edition
If the reader encounters a macro character, then the function associated with that macro character is invoked and may produce an object to be returned. This function may read following characters in the stream in whatever syntax it likes (it may even call read recursively) and return the object represented by that syntax. Macro characters may or may not be recognized, of course, when read as part of other special syntaxes (such as for strings).
The reader is therefore organized into two parts: the basic dispatch loop, which also distinguishes symbols and numbers, and the collection of macro characters. Any character can be reprogrammed as a macro character; this is a means by which the reader can be extended. The macro characters normally defined are as follows:
(a b c)
is read as a list of three objects (the symbols a, b, and c). The right parenthesis need not immediately follow the printed representation of the last object; whitespace characters and comments may precede it. This can be useful for putting one object on each line and making it easy to add new objects:
(defun traffic-light (color) (case color (green) (red (stop)) (amber (accelerate)) ;Insert more colors after this line ))
It may be that no objects precede the right parenthesis, as in () or ( ); this reads as a list of zero objects (the empty list).
If a token that is just a dot, not preceded by an escape character, is read after some object, then exactly one more object must follow the dot, possibly followed by whitespace, followed by the right parenthesis:
(a b c . d)
This means that the cdr of the last pair in the list is not nil, but rather the object whose representation followed the dot. The above example might have been the result of evaluating
(cons 'a (cons 'b (cons 'c 'd))) => (a b c . d)
Similarly, we have
(cons 'znets 'wolq-zorbitan) => (znets . wolq-zorbitan)
It is permissible for the object following the dot to be a list:
(a b c d . (e f . (g)))
is the same as
(a b c d e f g)
but a list following a dot is a non-standard form that print will never produce.
;;;; COMMENT-EXAMPLE function. ;;; This function is useless except to demonstrate comments. ;;; (Actually, this example is much too cluttered with them.) (defun comment-example (x y) ;X is anything; Y is an a-list. (cond ((listp x) x) ;If X is a list, use that. ;; X is now not a list. There are two other cases. ((symbolp x) ;; Look up a symbol in the a-list. (cdr (assoc x y))) ;Remember, (cdr nil) is nil. ;; Do this when all else fails: (t (cons x ;Add x to a default list. '((lisp t) ;LISP is okay. (fortran nil) ;FORTRAN is not. (pl/i -500) ;Note that you can put comments in (ada .001) ; "data" as well as in "programs". ;; COBOL?? (teco -1.0e9))))))
In this example, comments may begin with one to four semicolons.
The ATSIGN listing program, alas, is no longer in use, but EMACS is widely available, especially the GNU EMACS implementation, which is available from the Free Software Foundation, 675 Massachusetts Avenue, Cambridge, Massachusetts 02139. Remember, GNU's Not UNIX.
`(cond ((numberp ,x) ,@y) (t (print ,x) ,@y))
is roughly equivalent to writing
(list 'cond (cons (list 'numberp x) y) (list* 't (list 'print x) y))
The general idea is that the backquote is followed by a template, a picture of a data structure to be built. This template is copied, except that within the template commas can appear. Where a comma occurs, the form following the comma is to be evaluated to produce an object to be inserted at that point. Assume b has the value 3; then evaluating the form denoted by `(a b ,b ,(+ b 1) b) produces the result (a b 3 4 b).
If a comma is immediately followed by an at-sign (@), then the form following the at-sign is evaluated to produce a list of objects. These objects are then ``spliced'' into place in the template. For example, if x has the value (a b c), then
`(x ,x ,@x foo ,(cadr x) bar ,(cdr x) baz ,@(cdr x)) => (x (a b c) a b c foo b bar (b c) baz b c)
The backquote syntax can be summarized formally as follows. For each of several situations in which backquote can be used, a possible interpretation of that situation as an equivalent form is given. Note that the form is equivalent only in the sense that when it is evaluated it will calculate the correct result. An implementation is quite free to interpret backquote in any way such that a backquoted form, when evaluated, will produce a result equal to that produced by the interpretation shown here.
(append [x1] [x2] [x3] ... [xn] (quote atom))
where the brackets are used to indicate a transformation of an xj as follows:
(append [x1] [x2] [x3] ... [xn] form)
where the brackets indicate a transformation of an xj as described above.
(apply #'vector `(x1 x2 x3 ... xn))
No other uses of comma are permitted; in particular, it may not appear within the #A or #S syntax.
Anywhere ``,@'' may be used, the syntax ``,.'' may be used instead to indicate that it is permissible to destroy the list produced by the form following the ``,.''; this may permit more efficient code, using nconc instead of append, for example.
If the backquote syntax is nested, the innermost backquoted form should be expanded first. This means that if several commas occur in a row, the leftmost one belongs to the innermost backquote.
Once again, it is emphasized that an implementation is free to interpret a backquoted form as any form that, when evaluated, will produce a result that is equal to the result implied by the above definition. In particular, no guarantees are made as to whether the constructed copy of the template will or will not share list structure with the template itself. As an example, the above definition implies that
`((,a b) ,c ,@d)
will be interpreted as if it were
(append (list (append (list a) (list 'b) 'nil)) (list c) d 'nil)
but it could also be legitimately interpreted to mean any of the following.
(append (list (append (list a) (list 'b))) (list c) d) (append (list (append (list a) '(b))) (list c) d) (append (list (cons a '(b))) (list c) d) (list* (cons a '(b)) c d) (list* (cons a (list 'b)) c d) (list* (cons a '(b)) c (copy-list d))
(There is no good reason why copy-list should be performed, but it is not prohibited.)
After I gained some experience in writing nested backquote forms, I found that I was not stopping to analyze the various patterns of nested backquotes and interleaved commas and quotes; instead, I was recognizing standard idioms wholesale, in the same manner that I recognize cadar as the primitive for ``extract the lambda-list from the form ((lambda ...) ...))'' without stopping to analyze it into ``car of cdr of car.'' For example, ,x within a doubly-nested backquote form means ``the value of x available during the second evaluation will appear here once the form has been twice evaluated,'' whereas ,',x means ``the value of x available during the first evaluation will appear here once the form has been twice evaluated'' and ,,x means ``the value of the value of x will appear here.''
See appendix C for a systematic set of examples of the use of nested backquotes.
The # character also happens to be a non-terminating macro character. This is completely independent of the fact that it is a dispatching macro character; it is a coincidence that the only standard dispatching macro character in Common Lisp is also the only standard non-terminating macro character.
See the next section for predefined # macro-character constructions.