ELisp编程十三:宏二

为什么分两个步骤:先展开宏,再求值。

因为单单有一个宏定义(这里称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)


你可能感兴趣的:(编程,C++,list,编译器)