混乱は、マクロがプリプロセッサであるということです。実行時の値を知るための組み込みのメカニズムがありません。したがって、この用語を使用する場合:
(test-macro 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)
2番目のバージョンに関して:マクロ:
(defmacro test-macro (xlist)
`(,@xlist))
と同等です:
(defmacro test-macro (xlist)
xlist)
そのため、最初のバージョンで受け取ったエラーは発生しません。