In my answer to a Code Review.SE question, I suggested that the OP might consider using records to represent chess pieces. Since the piece records would all be the same, except for the name, I figured I could generate them programmatically, like this:
(map #(defrecord % [color])
["Rook" "Pawn" "Queen" "King" "Knight" "Bishop"])
That sort of worked, but my record names weren't the piece names; they were random gensyms: instead of user.Rook
I got user.p1__910
. If I did (p1__910. :black)
, it did work and create a record, but you can probably see why I wasn't satisfied with that.
I also tried the following two variations:
(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)
What's wrong with my approach? How can I generate a bunch of identical records from a list of names? Is this even possible?
This is a classic case of macro-contagion.
user> defrecord
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/defrecord, compiling:(/tmp/form-init802461651064926183.clj:1:5990)
You where very close with the (symbol %)
idea you just needed to make it so the defrecord expressions generated are evaluated after you provide the values.
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
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句