使用 Peter Seibel 的 defclass 宏的插槽引用列表



我使用的是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在编译时执行符号定义(defvardefparameter,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+)

最新更新