簡體   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