2014-04-01 43 views
2

我想寫一個類似宏(我認爲)在函數中的線程宏,但是這將允許我指定一個關鍵字在哪裏會發生以前的窗體的插入。我打算使用clojure.walk/prewalk-replace,但我得到了clojure.lang.ArityException。下面是代碼:
遞歸宏arityexception

(defmacro streamops [data form] 
    (let [keewurd :...] 
    (cond 
     (not (seq? form)) form 
     (= (count form) 0) data 
     :else (streamops ~(clojure.walk/prewalk-replace 
          {keewurd data} (first form)) 
         ~(rest form)))))` 

但是當我嘗試應用單元測試:

(= (macroexpand '(streamops 3 ((+ 1 :...) (* :... 2)))) 
    '(* (+ 1 3) 2)) 

它產生:

clojure.lang.ArityException: Wrong number of args (-1) passed to: walk$prewalk-replace 
     Compiler.java:6473 clojure.lang.Compiler.macroexpand1 
      core.clj:3633 clojure.core/macroexpand-1 
      core.clj:3642 clojure.core/macroexpand 

我在做什麼錯?

+0

在另一方面,看看[瑞士箭頭(https://github.com/rplevy/swiss-arrows#a-generalization-of-這個箭頭),有一個宏可以完成你想要完成的任務。 – xsc

回答

1

您的宏的定義中似乎有一個錯誤的語法引用`,因爲它在您發佈的代碼中放置在它的末尾,但在您使用unquote的表單中沒有語法引用~

下面的作品就好了:

(defmacro streamops [data form] 
    (let [keewurd :...] 
    (cond 
     (not (seq? form)) form 
     (= (count form) 0) data 
     :else `(streamops ~(clojure.walk/prewalk-replace 
          {keewurd data} (first form)) 
         ~(rest form))))) 

(= (macroexpand '(streamops 3 ((+ 1 :...) (* :... 2)))) 
    '(* (+ 1 3) 2)) 

;= true 
+0

第一次宏展開後,代碼是否被重新評估爲宏擴展?這似乎是返回一個包含宏的表單,然後它不會被評估,因爲它是作爲普通代碼返回的。 – DJD

+0

是的,代碼被重新評估,並且'macroexpand'的結果返回'(*(+ 1 3)2)'。此外,如預期的那樣,使用'macroexpand-1'返回'(user/streamops(+ 1 3)((*:... 2)))''。 –