我使用的是Practical Common Lisp中的defclass宏,它以符号列表为参数。
我想更改宏,使其接受引用的符号列表。这样做的好处是将thenm定义为可以在其他方便函数中使用的常数,例如这里。我在努力完成这件事时弄糊涂了。
我的用例如下:
(defconstant state-slots '(unit motion mode moc-offset woc-pos woc-inc feed spindle))
;; would like to use the quoted list here:
(defclass-by-slots gc-state (unit ; :mm(=G21) :inch(=G20)
motor ; nil :on
motion ; :jog(=G0) :lin(=G1) :cw(=G2) :ccw(=G3)
mode ; :abs(=G90) :inc(=G91)
moc-offset ; woc-zero(xyz, mm) from moc-zero
woc-pos ; woc-pos(xyz, mm) from woc-zero
woc-inc
feed
spindle))
;; can use quoted slot list when using a convenience function, e.g:
(defun format-by-slots (o slots &optional str-type)
(let* ((f (lambda (s$) (eval (format-slot o s$))))
(str-type (string-upcase str-type))
(r (concatenate
'string
(format nil "~A (~A)" o (class-of o))
(reduce (lambda (s1 s2) (concatenate 'string s1 s2))
(loop for s in slots
when (funcall f s) collect it)
:from-end t :initial-value (format nil "~%")))))
(if str-type
(ppcre:regex-replace-all
(format nil "^#<~A \{(\d|[A-F])+\}> " str-type)
r
(format nil "#<~A {...}> " str-type))
r)))
我将它用于由不同插槽定义的几个类。
令人讨厌的是,我无法为类型定义和方便功能统一定义插槽,这是令人讨厌的错误的来源。
基于[Rainer Joswig的答案]的解决方案(https://stackoverflow.com/a/61154538/2336738):
(defmacro def-my-class (name supers slots-symbol)
"The value of a symbol of slots-symbol is used as the
list of slots."
`(defclass ,name ,supers
,(if (and (symbolp slots-symbol)
(symbol-value slots-symbol)
(listp (symbol-value slots-symbol)))
(mapcar #'slot->defclass-slot (symbol-value slots-symbol))
(error "~a is not a symbol which names a list of slot names" slots-symbol))))
编译时的符号值
如果要在编译时使用符号的值,则需要确保已定义该值。两种常见的方法:
-
在编译另一个使用的文件之前,在文件中定义符号并加载它
-
使用
EVAL-WHEN
在编译时执行符号定义(defvar
、defparameter,
defconstant `…(
读取时间评估
在编译期间使用符号值的一种可能性是使用读取时间评估。您需要确保在编译期间定义了+state-slots+
的常数值:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +state-slots+
'(unit motion mode moc-offset woc-pos woc-inc feed spindle)))
(defclass foo ()
#.+state-slots+)
自定义宏
如果+state-slots+
的值是在编译时定义的,那么我们也可以在宏中使用它:
(defmacro def-my-class (name supers slots-symbol)
"The value of a symbol of slots-symbol is used as the
list of slots."
`(defclass ,name ,supers
,(if (and (symbolp slots-symbol)
(symbol-value slots-symbol)
(listp (symbol-value slots-symbol)))
(symbol-value slots-symbol)
(error "~a is not a symbol which names a list of slot names"))))
(def-my-class foo () +state-slots+)