0

マクロを使用してクラス インスタンスを作成したいと考えています。

つまり、次のような式を作成したいということです。

(make-instance 'message :id id :mid mid) 

このようにクラスを定義します。

(defclass message ()
  ((id
     :initarg :id
     :initform 0
     :accessor id)
   (mid
     :initarg :mid
     :initform 0
     :accessor mid)))

(defmethod print-object ((obj message) stream)
   (print-unreadable-object (obj stream :type t)
      (with-slots (id mid) obj
         (format stream "~A  ~A " id mid))))

そしてマクロはこんな感じ。

 (defun slotlist (alist)
    (mapcan
       #'(lambda (x)
            (let* ((s (closer-mop:slot-definition-name x))
                   (k (intern (symbol-name s) :keyword))
                   (v (assoc k alist)))
                   (if v (list k (cdr v)))))
                (closer-mop:class-direct-slots (find-class 'message))))

(defmacro create-message (alist)
    (let ((a (gensym)))
       `(let ((,a (slotlist ,alist)))
            (make-instance 'message ,@a))))

そして次のようなjson-obj:

(setq json-obj '((:id . 1) (:mid . 2)))

マクロ create-message を適用すると

(create-message json-obj)

次のように展開します。

(LET ((#:G1111 (SLOTLIST JSON-ALIT)))
   (MAKE-INSTANCE 'MESSAGE . #:G1111))

ただし、インスタンスの値が # であることを示しているため、インスタンスは正しく初期化されません。

map 関数の文字列をつなぎ合わせて apply 関数を使用する必要がありますか?

4

5 に答える 5

1

あなたのユースケースについて何か重要なことを見逃しているかもしれませんが、あなたが望むものは関数として簡単に実装できるようです。

新しいmessageインスタンスを作成するには、 のようなものが必要です(make-instance 'message :id 1 :mid 2)。この情報はすべてjson-obj入っています -- 正しい形式に変換して : を使用するだけapplyです。

(defun json-attr->arg-list (json-attr)
  (list (car json-attr)
        (cdr json-attr)))

(defun json-obj->arg-list (json-obj)
  (apply #'concatenate 'list
         (map 'list #'json-attr->arg-list json-obj)))

(defun create-message (json-obj)
  (apply #'make-instance 'message (json-obj->arg-list json-obj)))

create-messageこれで、以前に定義した で呼び出すことができますjson-obj:

=> (create-message json-obj)

#<MESSAGE 1  2 >

さて、これをマクロとして実装できますが、ポイントは何でしょうか? before run-timeの値を知ることはできないjson-objため、コンパイル時に実行できることは、基本的に、作成したばかりの関数をインライン化すること以外にはありません。ただし、(a) この場合、測定可能な量だけパフォーマンスが向上する可能性は低く、(b) それはマクロの目的ではありません。インライン化にはコンパイラ ヒントを使用してください。

create-messageさらに、高階関数で使用したい場合は、関数として実装する必要があります。たとえば、連想リストのリストからオブジェクト(map 'list #'create-message list-of-json-objs)のリストを作成するには、非常に便利な方法です。messagecommon-lisp では、シンボルにマクロと関数の両方を関連付けることができるため、マクロと関数の両方のバインドを作成できます。しかし、マクロを使用しても何の利点も得られないため、自分で作業を増やすだけです。

于 2013-11-15T18:52:08.737 に答える
0

を使用してこれを行う方法は次のとおりですcl-json

(ql:quickload "cl-json")

(defclass message ()
  ((id :initarg :id :initform 0 :accessor id)
   (mid :initarg :mid :initform 0 :accessor mid)))

(cl-json:encode-json (make-instance 'message :mid 42 :id 13))
{"id":13,"mid":42}

本当にそれだけです。ここでもっと読みたいと思うかもしれません: http://common-lisp.net/project/cl-json/#STREAMING-APIゼロから書くのに費やす)。


余談ですが、JSON はよく宣伝されているため、実際にはそれほど優れたものではありません。形式を自由に選択できる場合は、Protobuf または Trift を見てください (これらも悪いですが、JSON ほど悪くはありません) :)

于 2013-11-16T20:21:47.113 に答える
0

何をしようとしているのかわからないので、適用機能を使用する必要があるかどうかはわかりません。ただし、コードの問題が 1 つあります。

あなたが与えたコードには、で始まる準引用符があります

`(let ((,insym ,json-obj))

次に、次の形式で準引用符から脱出します。

,(mapcan #'(lambda (x)

1 レベルの準引用符と、それに一致する 1 つの引用符解除 (コンマ) があります。そのため、マクロが展開されたときにそのフォームが評価されます。しかし、同じ引用符のないフォーム内で、別のフォームの引用符を外そうとします。

,insym

単一レベルの準引用からすでに脱出しているため、これはエラーです。このエラーを修正するには (マクロ全体ではないかもしれませんが)、最後のコンマを削除する必要があります。

この論文は、準引用についての詳細を学ぶのに役立つかもしれません: http://repository.readscheme.org/ftp/papers/pepm99/bawden.pdf

于 2013-11-15T03:57:21.667 に答える