Macros 使用宏创建记录

Macros 使用宏创建记录,macros,clojure,record,Macros,Clojure,Record,我有一个记录(defcrecord Rec[id]) 我用它来工作 (def my ( Rec. 2 )) (println (:id my)) 现在我想用宏替换记录定义。这样我就可以写 (r 2) (println (:id my)) 我写了宏 (defmacro r [id] (list 'def 'my (symbol "(") 'Rec. id (symbol ")"))) 我用macroexpand检查过了 (macroexpand-1 '(r 2)) => (d

我有一个记录
(defcrecord Rec[id])

我用它来工作

(def my ( Rec. 2 ))
(println (:id my))

现在我想用宏替换记录定义。这样我就可以写

(r 2) 
(println (:id my))
我写了宏

(defmacro r [id]
   (list 'def 'my (symbol "(") 'Rec. id (symbol ")")))
我用macroexpand检查过了

(macroexpand-1 '(r 2))  => (def my ( Rec. 2 ))

但是我得到了
运行时异常:在
(r2)
上定义的参数太多,从左参数创建符号与使用左参数评估文本不同。前者没有特别的意义;后者导致读取器生成一个嵌套列表,然后对其进行计算

换句话说,Clojure评估的是数据结构,而不是文本(或符号列表)。当您在REPL中键入某个内容时,该文本将被读入数据结构,然后对该数据结构进行求值

要使其正常工作,宏本身需要生成嵌套列表:

(defmacro r [id]
  (list 'def 'my (list 'Rec. id)))
或者更好地使用语法quote运算符:

(defmacro r [id]
  `(def my (Rec. ~id)))
为了便于说明,您可以看到当Clojure代码被读取为文本时会发生什么:

(read-string "(def my (Rec. 2))")
=> (def my (Rec. 2))
(map type (read-string "(def my (Rec. 2))"))
=> (clojure.lang.Symbol clojure.lang.Symbol clojure.lang.PersistentList)

“现在我想用宏替换记录定义。”为什么?@Alex Taggart,因为我想创建一个类似DSL的东西。同时,所讨论的例子也被简化了。