1

我正在使用 common lisp,发现自己经常输入以下形式的插槽定义:

(name :initarg :name :accessor name)

所以我想编造一个宏来加速这个。我想出了以下内容:

(defmacro quickslot (name)
`(,name :initarg ,(intern (string-upcase name) "KEYWORD") :accessor ,name))

毫无疑问,这是一个肮脏的黑客,但很实用。或者我是这么想的。当我试图运行我的代码时,我遇到了一个障碍:因为 defclass 是一个宏,所以传递给它的参数是未经评估的。这意味着,而不是看到

(x :initarg :x :accessor x)

它看到

(quickslot x)

当然,这表明一个错误。

在我看来,答案是以某种方式控制宏扩展的顺序,以确保在 defclass 之前扩展快速槽。这让我想到了我的问题:如何做到这一点?或者,如果您对我最初的难题有不同的解决方案,那也不会不受欢迎。

4

3 回答 3

4

这真的不值得一个宏。宏通常将文字 Lisp 源代码作为输入。

相反,您可以只使用一个函数。来自实用通用 Lisp,第 24 章

(defun as-keyword (sym) (intern (string sym) :keyword))

(defun slot->defclass-slot (spec)
  (let ((name (first spec)))
    `(,name :initarg ,(as-keyword name) :accessor ,name)))

然后你可以做类似的事情(再次改编自PCL):

(defmacro my-defclass (name slots)
  `(defclass ,name ()
     ,(mapcar #'slot->defclass-slot slots)))
于 2012-12-27T08:23:51.213 回答
1

不,你不能这样做。不过,您可以编写一个宏defclass(这对您的快速插槽有一些特殊的语法)。

于 2012-12-26T23:37:28.777 回答
1

您可以完全以不同的方式解决问题,并提出一个阅读器宏,指示阅读器调用其后面macroexpand的代码,这将比在类中声明槽的唯一目的更通用。但是完整的解决方案会有些涉及,因为您必须考虑读者的许多特点和要求,但是,即使是像这样丑陋的东西也可以完成这项工作:

(defmacro quickslot (name)
`(,name :initarg ,(intern (string-upcase name) "KEYWORD") :accessor ,name))

(macroexpand '(defclass test-class ()
               (#.(macroexpand '(quickslot some-slot)))))

所以,你必须做的就像一个别名#.(macroexpand ...)


而且...给你:

(set-macro-character
 #\{
 #'(lambda (str char)
     (declare (ignore char))
     (let ((*readtable* (copy-readtable *readtable* nil))
           (reading-p t))
       (set-macro-character
        #\}
        #'(lambda (stream char)
            (declare (ignore char stream))
            (setf reading-p nil)))
       (loop for exp = (read str nil nil t)
          while reading-p
          collect (macroexpand exp)))))

(read-from-string "'(defclass test-class ()
               {(quickslot some-slot)
               (quickslot some-other-slot)})")
'(DEFCLASS TEST-CLASS NIL
           ((SOME-SLOT :INITARG :SOME-SLOT :ACCESSOR SOME-SLOT)
            (SOME-OTHER-SLOT :INITARG :SOME-OTHER-SLOT :ACCESSOR
             SOME-OTHER-SLOT)))

:)

于 2012-12-27T09:09:52.860 回答