简体   繁体   English

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

[英]unquoting argument in macro doesn't work as expected

I have the following Clojure macro: 我有以下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))))

and I'm trying to use it like this: 我正在尝试像这样使用它:

(deftest with-model-test
  (with-model sandwich
    (let [nodes (-> sandwich .listObjects iterator-seq)]
      (is nodes))))

or this: 或这个:

(deftest with-model-test
  (with-model sandwich [*ds* "named-model"]
    (let [nodes (-> sandwich .listObjects iterator-seq)]
      (is nodes))))

The idea being that sandwich should now refer to a Model , but I get a runtime exception: 这个想法是, sandwich现在应该引用Model ,但是出现运行时异常:

Unable to resolve symbol: sandwich in this context

If I (println ~ref) in the macro, I get the model instance. 如果我在宏中(println ~ref) ,我将得到模型实例。 If I (println '~ref) I get sandwich . 如果我(println '~ref)我得到sandwich How should I be going about this instead? 我应该怎么做呢?

The macroexpansion when using the with-model macro as (with-model sandwich (let [node (-> sandwich)])) looks like this (with namespaces removed, let binding names shortened and some formatting): 当将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)])))

As you can see sandwich is being used in the let before it is defined, since the macro generates code that figures stuff out about the second argument after the expansion. 如您所见,在定义let之前,将在sandwich中使用sandwich ,因为宏会生成代码,用于计算扩展后第二个参数的内容。 A way to go around this is to have the macro figuring things out before the expansion. 解决此问题的一种方法是让宏在扩展之前弄清楚事情。 In general I try to do this in order to have a simpler expansion even though it sometimes implies a more complicated macro code, not in this case tough. 总的来说,我尝试这样做是为了使扩展更简单,即使它有时意味着更复杂的宏代码,在这种情况下也不难。

(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