开发者

Macros iterating over undefined Symbols

开发者 https://www.devze.com 2023-03-26 05:31 出处:网络
开发者_JS百科When applying a macro multiple times with a another macro, bare Symbols are not inserted into the current context:

开发者_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.

0

精彩评论

暂无评论...
验证码 换一张
取 消