用于创建记录的Clojure宏

Ves*_*sna 0 macros record clojure

我写了一个用于创建记录的宏

(defmacro def-entity [name & value]
 `(do
    (defrecord ~name (vector  ~@value))
    ))
Run Code Online (Sandbox Code Playgroud)

我创建了一个实体

(def-entity p a b)
Run Code Online (Sandbox Code Playgroud)

但是当我尝试创建一个具体的实例(def something(p."a""b"))时,我收到此消息java.lang.IllegalArgumentException:找不到类user.p(repl-1:40)的匹配ctor.所以我必须提供3个参数,像这样(def某人(p."a""b""x"))并且它放置像这样的值

 (-> someone :a)
 "b"
 (-> neko :p)
 nil
Run Code Online (Sandbox Code Playgroud)

我似乎不明白发生了什么?

sku*_*uro 5

由于defrecord它本身就是一个宏,并希望记录的字段作为矢量文字传递,你应该更好地避免传递一个引用向量的符号,并真正构建一个矢量文字作为宏工作的一部分:

(defmacro defentity [name & values]
  `(defrecord ~name ~(vec values)))
Run Code Online (Sandbox Code Playgroud)

结果如下:

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"}
Run Code Online (Sandbox Code Playgroud)

相反,您的版本会产生以下结果,它不使用矢量文字作为输入defrecord:

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

事实上,我甚至无法在Clojure 1.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) 
Run Code Online (Sandbox Code Playgroud)