自定义宏

<实用Common.Lisp编程> 第8章 如何自定义宏
 
1.宏的展开期和运行期
  理解宏的关键在于必须清楚地知道那些生成代码的代码(宏)和那些最终构成程序的代码(所有其他内容)之间的区别。当编写宏时,你是在编写那些将被编译器用来生成代码并随后编译的程序。只有当所有的宏都被完全展开并且产生的
代码被编译后,程序才可以实际运行。宏运行的时期被称为宏展开期(macro expansion time),这和运行期(runtime)是不同的,后者是正常的代码(包括那些有宏生成的代码)实际运行的阶段。
  牢记这一区别很重要,因为运行在宏展开期的代码与那些运行在运行期的代码相比,它们的运行环境不同。也就是说,在宏展开期无法访问那些仅存在于运行期的数据。
  当Lisp被解释而非编译时,宏展开期和运行期之间的区别不甚明显,因为它们临时纠缠在了一起。同样,语言标准并未规定解释器处理宏的具体方式——它可能 在被解释的形式中展开所有的宏,然后解释执行那些宏所生成的代码,也可能是直接解释一个形式并在每次遇到宏的时候展开。无论哪种情况,总是还有宏传递那些 代表宏形式的未经求值的Lisp对象,并且宏的作用仍然是生成做某些事情的代码,而非直接做任何事情。
 
2.编写宏的步骤:
(1)编写示例的宏调用以及它应当展开成的代码,反之亦然;
(2)编写示例调用的参数中生成手写展示式的代码;
(3)确保宏抽象不产生“泄露”。
 
3.编写宏的注意点
(1)除非有特殊理由,否则需要将需要展示式中的任何子形式放在一个位置上,使其求值顺序与宏调用的子形式相同。
(2)除非有特殊理由,否则需要确保子形式仅被求值一次,方法是在展开式中创建变量来持有求值参数形式所得到的值,然后在展开式中所有需要用到该值的地方使用这个变量。
(3)在宏展开期使用GENSYM来创建展开式中用到的变量名。
 (defmacro with-gensyms ((&rest names) &body body) `(let ,(loop for n in names collect `(,n (gensym)))) ,@body) 自定义宏
posted @ 2013-03-17 11:09  登山者  阅读(297)  评论(0编辑  收藏  举报