为什么分两个步骤:先展开宏,再求值。
因为单单有一个宏定义(这里称macro body)是不能在编译时求值的,宏的参数还没呢。宏的参数必须要等到编译器看到宏调用代码的时候才能知道。因此将宏参数传递给宏定义,然后展开宏再求值,是唯一能行的方法。
很好理解,这里就像C++的一样。
反引号(Backquote)`
最简单的情况下,和‘功能相同,代表不要对一个list求值
`(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
'(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
上面两个表达式是等价的。
下面的宏
(defmacro inc (var)
(list 'setq var (list '1+ var)))
用反引号的简化写法是:
(defmacro inc2 (var)
`(setq ,var (1+ ,var)))
反引号的特殊在于如果在里面的list中使用,号,会告诉编译器如何展开该宏:
1.将,后面的求值,
2.用值来替换该处的原表达式
`(a list of ,(+ 2 3) elements)
⇒ (a list of 5 elements)
这里,(+2 3) 被求值成了5,5就作为一个元素加入到这个list中。
这种用法可以应用在定义宏的时候,请注意差别很大。
(defmacro t-becomes-nil (variable)
`(if (eq ,variable t)
(setq ,variable nil)))
(macroexpand '(t-becomes-nil foo))
这句宏调用展开后等价于:
(if (eq foo t) (setq foo nil))
如果将宏定义中的,去掉,等价于:
(if (eq varialbe t) (setq variable nil))
此处没有求值。
`后面的表达式里面可以用,@符号表示将一个list的值添加进来,比如:
(setq some-list '(2 3))
⇒ (2 3)
`(1 ,@some-list 4 ,@some-list)
⇒ (1 2 3 4 2 3)
可读性大大加强,另一种可读性差的写法:
(cons 1 (append some-list '(4) some-list))
⇒ (1 2 3 4 2 3)