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