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

1

macroexpandまったく別の方法で問題に取り組み、リーダーにそれに続くコードを呼び出すように指示するリーダー マクロを考え出すことができます。これは、クラス内のスロット宣言の 1 つの目的よりも一般的です。しかし、読者の多くの特殊性と要求を説明する必要があったため、完全な解決策は多少複雑になります。

(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 に答える
1

いいえ、できません。ただし、代わりにマクロを書くこともできdefclassます (これには、クイックスロット用の特別な構文があります)。

于 2012-12-26T23:37:28.777 に答える