destructuring-bind
提供的基本树解构。例如,用于根据模板对结构对象的字段进行解构的宏如下(在with-slots
CLOS宏之后进行模式化):
(defmacro with-structure ((name . fields) struct &body body)
"Destructuring bind for the fields of a structure object."
(let ((gs (gensym)))
`(let ((,gs ,struct))
(symbol-macrolet ,(mapcar #'(lambda (f)
`(,f (,(mksymbol name f) ,gs)))
fields)
,@body))))
(defun mksymbol (&rest args)
"Creates a symbol by concatenating the arguments."
(values (intern (apply #'mkstring args))))
(defun mkstring (&rest args)
"Concatenates arguments into a string."
(with-output-to-string (stream)
(dolist (arg args)
(princ arg stream))))
现在:
(defstruct person name age)
PERSON
(defparameter p1 (make-person :name "Eli" :age 19))
P1
(with-structure (person- age) p1 (incf age))
20
p1
#S(PERSON :NAME "Eli" :AGE 20)
Graham还提供单独的宏模板,用于解构其他一些对象,如序列和数组。我的问题是关于添加另一层抽象是否合理,并使用类似(defmacro with-object (pattern (object type) &body body) ...)
的定义将这些各种宏合并到一个调用中。这类似于编写泛型函数,其中每个要解构的对象将使用适当的类型/类扩展。但是,宏扩展阶段似乎可能需要包含一些增量编译以确定对象类型(除非它是由用户声明的)。编译可以与扩展交错,以实现这样的"泛型"操作;还是有更简单的方法?