在我对a Code Review.SE question的回答中,我建议OP可能会考虑使用记录来表示棋子。由于片段记录都是相同的,除了名称,我想我可以通过编程生成它们,如下所示:
(map #(defrecord % [color])
["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"])
那种方式有效,但我的唱片名称不是片名;他们是随机的gensyms:而不是user.Rook
我得到user.p1__910
。如果我做(p1__910. :black)
,它确实有效并创建了一条记录,但你可能会明白为什么我对此并不满意。
我还尝试了以下两种变体:
(map #(defrecord % [color])
['Rook 'Pawn 'Queen 'King 'Knight 'Bishop])
;; Same result as above.
(map #(defrecord (symbol %) [color])
["Rook" "Knight" "Pawn" "Queen" "King" "Bishop"])
;; CompilerException java.lang.ClassCastException: clojure.lang.PersistentList
;; cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:1:7)
我的方法有什么问题?如何从名单列表中生成一堆相同的记录?这甚至可能吗?
答案 0 :(得分:5)
这是宏观传染的经典案例。
user> defrecord
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/defrecord, compiling:(/tmp/form-init802461651064926183.clj:1:5990)
你最接近于你需要的(symbol %)
想法,以便在你提供值后评估生成的defrecord表达式。
user> (defmacro make-pieces [piece-names]
`(do ~@(map #(list 'defrecord (symbol %) '[color])
piece-names)))
#'user/make-pieces
user> (macroexpand-1 '(make-pieces ["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"]))
(do (defrecord Rook [color])
(defrecord Pawn [color])
(defrecord Queen [color])
(defrecord King [color])
(defrecord Knight [color])
(defrecord Bishop [color]))
user> (make-pieces ["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"])
user.Bishop
答案 1 :(得分:5)
如果所有记录都相同,为什么要给他们不同的名字?我建议:
(defrecord Chess-Piece [name color])
您的方法出了什么问题,defrecord
是一个宏,因此“name”参数被解释为符号,因此在编译之前确定记录的名称。映射仅在运行时发生,在编译后。
匿名函数中的%
被重写为gensym(p1__910
),后者又被解释为命名新记录的符号。
你想要做的事情必须用宏来完成 - 你必须简单地确保在评估时(defrecord some-symbol [color])
(再次,这是预运行时),some-symbol
是什么你想要它。也许有些东西:
(defmacro defpieces [names]
(let [defs (map #(list 'defrecord (symbol %) '[color])
names)]
`(do ~@defs)))
您的代码如何被重写:
(map #(defrecord % [color])
["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"])
对于读者宏,这变成(粗略地):
(map (fn* [p1__910#] (defrecord p1__910# [color])
["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"])
defrecord
本身就是一个宏,所以(再次,在运行时之前),它会被转换为包含以下内容的巨大代码块:
(deftype* p1__910# user.p1__910# .....
要查看整个块,请使用非常有用的macroexpand:
(macroexpand '(defrecord p1__910# [color]))