严格来说,宏本身无法做到这一点;宏必须做的是生成代码,其中参数表达式以这样一种方式嵌入,即它们被求值,也以这样一种方式被引用。
鉴于(list-builder (+ x y) (+ y x) x)我们想生成此代码:(list '(+ x y) (+ x y) '(+ y x) (+ y x) 'x x).
我们可以将宏拆分为一个定义的顶级包装器defmacro和一个扩展器函数,该函数完成生成参数的大部分工作list;宏的主体只是将list符号粘贴在上面并返回它。
宏辅助函数必须eval-when在 Common Lisp 中进行一些包装,以确保它们在所有可能处理宏的情况下都可用:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun list-builder-expander (exprs)
(cond
((null exprs) nil)
((atom exprs) (error "list-builder: dotted syntax unsupported":))
(t (list* `',(car exprs) (car exprs)
(list-builder-expander (cdr exprs)))))))
(defmacro list-builder (&rest exprs)
(cons 'list (list-builder-expander exprs)))
一个“光滑”的实现,多合一defmacro,在一个反引号表达式中,可能是这样的:
(defmacro list-builder (&rest exprs)
`(list ,@(mapcan (lambda (expr) (list `',expr expr)) exprs)))
我们之前实现的“不支持点语法”检查现在变成了mapcan.
将lambda每个表达式E转换为列表((quote E) E)。 mapcan将这些列表连接在一起以形成 的参数list,然后将其拼接成(list ...)带有 的形式,@。
该表格`',expr从将报价简写应用于`(quote ,expr).