2014-02-22 52 views
0

我有以下的Clojure宏:unquoting說法是不正常工作

(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 [email protected])))) 

,我試圖用這樣的:

(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。我應該怎麼做呢?

回答

1

使用with-model宏作爲(with-model sandwich (let [node (-> sandwich)]))看起來像這樣(與命名空間去掉,讓縮短約束力的名字和一些格式)時,宏擴展:

(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)]))) 

正如你可以看到sandwichlet被使用之前,被定義,因爲宏生成的代碼在擴展之後會顯示關於第二個參數的內容。解決這個問題的一個方法是讓宏在擴展之前弄清楚事情。總的來說,我試圖做到這一點,以便進行更簡單的擴展,儘管它有時意味着更復雜的宏代碼,而不是強硬。

(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#)] 
     [email protected]))) 
+0

輝煌。特別爲解構幫助而感到高興。 – tjb1982