Macros iterating over undefined Symbols
开发者_JS百科When applying a macro multiple times with a another macro, bare Symbols are not inserted into the current context:
(defmacro ty [type]
`(deftype ~type []))
(defmacro empties [& args]
(doseq [arg args]
`(ty ~arg))
)
(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)
(derive ::Person ::Base)
(derive ::Animal ::Base)
(ty Me)
(prn ::Me)
(prn Me)
(empties Empty)
(prn ::Empty)
(prn Empty)
The last line gives: "Unable to resolve symbol: Empty in this context", even though when using the direct macro ty, it works. Any way to solve this? If possible without eval it would be much better.
(defmacro empties [& args]
(doseq [arg args]
`(ty ~arg)))
(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)
This is wrong. Your empties
call means that the macro expansion function for empties
gets as arguments the symbols Base
, Person
, and Animal
. It then evaluates the ty
macro call for each, but does not return anything, as doseq
always returns nil. So, the expanded code from that empties
call is nil. You need to return a single form from your macro function. You should wrap the multiple forms into a do
, and actually return all the subforms to that:
(defmacro empties [& args]
`(do ~@(map (fn [arg]
`(ty ~arg))
args)))
FWIW, I prefer to write @Svante's solution as
(defmacro empties [& args]
(cons `do
(for [arg args]
`(ty ~arg))))
which is also pretty close to the structure of your doseq
approach.
精彩评论