[英]unquoting argument in macro doesn't work as expected
我有以下Clojure宏:
(defmacro with-model
[ref & body]
`(tx
(let [ds# (when (vector? (first ~body)) (ffirst ~body))
name# (when (vector? (first ~body)) (second (first ~body)))
~ref (model ds# name#)]
(do ~@body))))
我正在尝试像这样使用它:
(deftest with-model-test
(with-model sandwich
(let [nodes (-> sandwich .listObjects iterator-seq)]
(is nodes))))
或这个:
(deftest with-model-test
(with-model sandwich [*ds* "named-model"]
(let [nodes (-> sandwich .listObjects iterator-seq)]
(is nodes))))
这个想法是, sandwich
现在应该引用Model
,但是出现运行时异常:
Unable to resolve symbol: sandwich in this context
如果我在宏中(println ~ref)
,我将得到模型实例。 如果我(println '~ref)
我得到sandwich
。 我应该怎么做呢?
当将with-model
宏用作(with-model sandwich (let [node (-> sandwich)]))
时with-model
宏扩展看起来像这样(删除了名称空间,使绑定名称缩短了,并采用了一些格式):
(macroexpand-1 '(with-model sandwich (let [node (-> sandwich)])))
(tx
(let [ds (when (vector? (first ((let [node (-> sandwich)]))))
(ffirst ((let [node (-> sandwich)]))))
name (when (vector? (first ((let [node (-> sandwich)]))))
(second (first ((let [node (-> sandwich)])))))
sandwich (model ds name)]
(let [node (-> sandwich)])))
如您所见,在定义let
之前,将在sandwich
中使用sandwich
,因为宏会生成代码,用于计算扩展后第二个参数的内容。 解决此问题的一种方法是让宏在扩展之前弄清楚事情。 总的来说,我尝试这样做是为了使扩展更简单,即使它有时意味着更复杂的宏代码,在这种情况下也不难。
(defmacro with-model
[ref & [x & _ :as body]]
`(tx
(let [ds# ~(when (vector? x) (first x))
name# ~(when (vector? x) (second x))
~ref (model ds# name#)]
~@body)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.