令人困惑的是宏是一个预处理器:它没有知道运行时值的内置机制。因此,当您使用该术语时:
(test-macro test-list)
宏看到的只是标识符test-list
:它预先不知道运行时值是一个列表,只知道源程序使用了这个变量标识符。
宏是源到源的重写器:它不知道程序的动态。更聪明的编译器可能能够看到 test-list 是一个常量并进行内联,但宏扩展器并不那么聪明。
您可以做的可能是这样的:
(defmacro test-macro (xlist)
(cond
(;; If we see test-macro is being used with a quoted list of things
;; then we can rewrite that statically.
(and (pair? xlist)
(eq? (car xlist) 'quote)
(list? (cadr xlist)))
`(list 'case-1 (* ,@(cadr xlist))))
(;; Also, if we see test-macro is being used with "(list ...)"
;; then we can rewrite that statically.
(and (pair? xlist)
(eq? (car xlist) 'list))
`(list 'case-2 (* ,@(cdr xlist))))
(else
;; Otherwise, do the most generic thing:
`(list 'case-3 (apply * ,xlist)))))
;; This hits the first case:
(test-macro '(3 4 5))
;; ... the second case:
(test-macro (list 5 6 7))
;; ... and the third case:
(defvar test-list '(1 100 2 200))
(test-macro test-list)
关于您的第二个版本:宏:
(defmacro test-macro (xlist)
`(,@xlist))
相当于:
(defmacro test-macro (xlist)
xlist)
所以这就是为什么您没有收到在第一个版本中收到的错误。