严格来说,宏本身无法做到这一点;宏必须做的是生成代码,其中参数表达式以这样一种方式嵌入,即它们被求值,也以这样一种方式被引用。
鉴于(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)
.