一、宏的引入
1.什么时候需要宏,宏可以做什么
优秀设计的一个通用原则就是:当你发现在程序中的几处都出现了相似的代码时,就应该写一个子例程,并把那些相似的语句换成对这个子例程的调用,lisp中可以使用宏,为我们创建上下文环境,或者利用宏,直接在上下文中计算。
宏可以控制 (或阻止) 对其参数的求值,并且它可以展开进入到主调方的上下文中。
宏的处理主要分为两步,宏展开(构造表达式)和求值(对展开的表达式求值)
二、宏的分类
1.创建上下文
(defmacro with-gensyms (syms &body body)
`(let ,(mapcar #'(lambda (sym) `(,sym (gensym)))
syms)
,@body))
前面约束系统中一些有用的创建上下文的宏,这些宏都极大简化了程序的编写
(defun as-keyword (sym) (intern (string sym) :keyword))
(defmacro defineclass (name slots)
`(defclass ,name ()
,(loop for slot in slots collect
(if (consp slot)
(let ((sname (first slot)) (value (second slot)))
`(,sname :initform ,value :initarg ,(as-keyword sname)
:accessor ,sname))
`(,slot :initarg ,(as-keyword slot) :accessor ,slot)))))
(defmacro declare-connectors (&rest connectors)
`(progn
,@(loop for c in connectors collect
`(defvar ,c (make-connector)))))
(defmacro declare-probes (&rest connectors)
`(progn
,@(loop for c in connectors collect
`(probe (string ',c) ,c))))
自动递归中定义了一个递归宏,当n个人分别要从n个choice中选取一个,如果每次都写代码,则很麻烦。
(defmacro var-choose-choices (choices (&rest choosers) &rest body)
(if (null choosers)
`(progn ,@body)
`(choose-bind ,(car choosers) ,choices
(var-choose-choices ,choices ,(cdr choosers) ,@body))))