在 Common Lisp 中,编写定义 class 的宏的最佳方法是什么?

In Common Lisp, what's the best way to write a macro that defines a class?

我正在尝试用 Common Lisp 编写一个宏,它定义了一个 class 和我指定的变量槽。到目前为止,一切正常(clisp 给我留下了深刻的印象!)为此:

(defmacro notifier (class slot) 
  "Defines a setf method in (class) for (slot) which calls the object's changed method."
   `(defmethod (setf ,slot) (val (item ,class))
     (setf (slot-value item ',slot) val)
     (changed item ',slot)))

(defmacro notifiers (class slots)
  "Defines setf methods in (class) for all of (slots) which call the object's changed method."
  `(progn 
     ,@(loop for s in slots collecting `(notifier ,class ,s))))

(defmacro defclass-notifier-slots (class nslots slots)
  "Defines a class with (nslots) giving a list of slots created with notifiers, and (slots) giving a list of slots created with regular accessors."
  `(progn
     (defclass ,class () 
       ( ,@(loop for s in nslots collecting `(,s :reader ,s)) 
         ,@(loop for s in slots collecting `(,s :accessor ,s))))
     (notifiers ,class ,nslots)))

问题是,现在我想创建的不只是 只是 我在调用宏时指定的插槽,而是其他一些具有变体名称的插槽。为了做到这一点,我必须使用一个丑陋的 "symbol-name, alter string, intern" 序列来生成变体名称作为插槽名称,而且我已经看到关于 SO 的答案说你应该避免这样做。那么有没有更好的方法呢?

在宏或其辅助函数之一中构造新符号没有错。

每当您多次需要某个东西或需要以某种方式记录它时,请编写一个函数。

由于我们需要使用可能是新的符号,因此确保符号位于正确的包中是有意义的。这里我们假设prefix符号的包就是正确的包。

(defun make-suffix-symbol (prefix suffix)
  (check-type prefix symbol)
  (check-type suffix (or string symbol))
  (when (symbolp suffix)
    (setf suffix (symbol-name suffix)))
  (intern (concatenate 'string
                       (symbol-name prefix)
                       suffix)
          (symbol-package prefix)))

CL-USER 12 > (make-suffix-symbol 'http-user::foo "BAR")
HTTP-USER::FOOBAR

或使用FORMAT:

(defun make-suffix-symbol (prefix suffix &optional (format-string "~A~A"))
   (check-type prefix symbol)
   (check-type suffix (or string symbol))
   (when (symbolp suffix)
     (setf suffix (symbol-name suffix)))
   (intern (format nil
                   format-string
                   (symbol-name prefix)
                   suffix)
           (symbol-package prefix)))

CL-USER 14 > (make-suffix-symbol 'http-user::foo "BAR" "~a-~a")
HTTP-USER::FOO-BAR