LISP 8.8 编写宏中宏

来源:互联网 发布:域名便宜 编辑:程序博客网 时间:2024/05/16 10:33

宏的作用是将常见的句法模式抽象掉,而反复出现在宏编写的特定模式同样也可受益于其抽象能力。

最后的几个do-primes函数中,都是以let形式确保子形式仅被求值一次的,引入了一些变量用来保存宏展开过程中用到的生成符号。

这也是一个常见模式,同样的也可以使用一个宏来将它抽象掉。


;;;编写宏中宏(defmacro with-gensyms ((&rest names) &body body)  `(let ,(loop for n in names collect `(,n (gensym)))     ,@body))(defmacro do-primes-4 ( (var start end) &body body)  (with-gensyms (ending-value)   `(do ((,var(next-prime ,start) (next-prime(1+ ,var)))  (,ending-value ,end)) ((> ,var ,ending-value))       ,@body)))


每个绑定形式由一个含有with-gensyms中的一个给定名字和字面代码(gensym)的列表所构成。

你可以通过将name替换成一个符号的列表,从而测试LOOP表达式生成的代码:

CL-USER> (loop for n in '(hello world) collect `(,n (gensym)))((HELLO (GENSYM)) (WORLD (GENSYM)))



下面的两份段话值得分析:

当编译关于do-primes的defmacro时,with-gensyms形式就被展开并被编译。

这样,do-primes的编译版本就已经跟你手写外层的let时一样。


当编译一个使用了do-primes的函数时,由with-gensyms生成的代码将会运行用来生成do-primes的展开式,

但with-gensyms宏本身在编译一个do-primes形式时并不会被用到,因为在do-primes被编译时,with-gensyms已经被展开。

原创粉丝点击