0

レコードを作成するためのマクロを作成しました

(defmacro def-entity [name & value]
 `(do
    (defrecord ~name (vector  ~@value))
    ))

そして私は1つのエンティティを作成しました

(def-entity p a b)

しかし、具体的なインスタンス(def something(p。 "a" "b"))を作成しようとすると、次のメッセージが表示されますjava.lang.IllegalArgumentException:クラスuser.p(repl-1:40)に一致するコンストラクターが見つかりません。したがって、次のような3つのパラメーターを指定する必要があります(def some(p。 "a" "b" "x"))そして、次のような値を入力します

 (-> someone :a)
 "b"
 (-> neko :p)
 nil

何が起こっているのかわからないようですが?

4

2 に答える 2

5

それdefrecord自体がマクロであり、レコードのフィールドがベクトルリテラルとして渡されることを期待しているため、ベクトルを参照するシンボルを渡すことは避け、マクロ作業の一部として実際にベクトルリテラルを作成する必要があります。

(defmacro defentity [name & values]
  `(defrecord ~name ~(vec values)))

その結果:

user=> (macroexpand-1 '(defentity p a b))
(clojure.core/defrecord p [a b])
user=> (defentity Test foo bar)
user.Test
user=> (def s (Test. "foo" "bar"))
#'user/s
user=> s
#user.Test{:foo "foo", :bar "bar"}

defrecord対照的に、ご使用のバージョンでは、次のようになります。これは、 :への入力としてベクトルリテラルを使用しません。

user=> (macroexpand-1 '(def-entity p a b))
(do (clojure.core/defrecord p (clojure.core/vector a b)))

実際、Clojure1.4ではあなたのバージョンを使用することさえできません。

user=> (def-entity w x y)
CompilerException java.lang.RuntimeException: Can't use qualified name as parameter: clojure.core/vector, compiling:(NO_SOURCE_PATH:1) 
于 2013-01-30T16:51:29.750 に答える
2

[~@value]の代わりに使用(vector ~@value)

(defmacro def-entity [name & value]
 `(do
    (defrecord ~name [~@value])
    ))

実際、あなたのバリアントは私にはまったく機能しません。(def-entity p a b)例外をスローします。しかし、それ自体をマクロに(def-entity p a b)展開し(defrecord p (vector a b))てdefrecordし、フィールドのリストとして2番目の引数を取ることを提案できます。2番目の引数は(vector a b)-それは3つの要素を含むリストです。したがって、vector、a、bの3つのフィールドを持つレコードが作成されます。(:vector someone)何が返されるかを確認してください。

于 2013-01-30T16:19:32.727 に答える