繁体   English   中英

宏中的取消引用参数无法按预期工作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM