Clojure中的动态记录

时间:2012-06-14 09:32:28

标签: clojure macros record

当我尝试从REPL运行以下代码时(使用动态记录):

(defrecord (symbol "rec2") (vec (map symbol ["f1" "f2"])))

我收到错误CompilerException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:23)

我问自己在哪里生成这个PersistentList,考虑到:

user=> (symbol "rec2")
rec2
user=> (vec (map symbol ["f1" "f2"]))
[f1 f2]

但我真正的问题是以下代码的工作原理:

user=> (defrecord rec2 [f1 f2])
user.rec2

我也试过了:

user=> (clojure.core/defrecord (clojure.core/symbol "rec1") (vec (clojure.core/map clojure.core/symbol ["f1" "f2"])))
CompilerException java.lang.RuntimeException: Can't refer to qualified var that doesn't exist, compiling:(NO_SOURCE_PATH:40)

(合格的var?唯一的区别是我完全符合函数名称WHICH EXIST,BTW) 显然我在理解Clojure defrecord宏时遗漏了一些东西,但是我觉得那个宏只是AST修饰符,所以如果我给它一个符号或某个解析为符号的东西它是同一个东西,所以我希望有人来解释我为什么正常形式有效而其他形式无效!

TIA!

1 个答案:

答案 0 :(得分:4)

问题如下:defrecord是一个宏,并且不评估所有参数。它们传递给宏,因此得到(symbol "rec2") - 包含2个元素的列表:符号和字符串,而不是rec2。您可以尝试以下操作:

(eval `(defrecord ~(symbol "rec2") ~(vec (map symbol ["f1" "f2"])))) 

创建列表(defrecord rec2 [f1 f2]),然后对其进行评估 但我不认为动态评估一些代码是个好主意。可能还有其他一些方法可以做到。