为什么分两个步骤:先展开宏,再求值。
因为单单有一个宏定义(这里称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)
这种用法可以应用在定义宏的时候,请注意差别很大。
(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)