рекурсивен макро arityexception

Опитвам се да напиша макрос, подобен (мисля) по функция на макроса за нишки, но това ще ми позволи да посоча ключова дума, където ще се случи вмъкването на предишния формуляр. Планирах да използвам clojure.walk/prewalk-replace, но получавам clojure.lang.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

какво правя грешно


person DJD    schedule 01.04.2014    source източник
comment
В друга бележка, погледнете swiss-arrows, има макрос, който прави това, което се опитвате да постигнете.   -  person xsc    schedule 01.04.2014


Отговори (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
person juan.facorro    schedule 01.04.2014
comment
Преоценява ли се кодът за макроразгъване след първото макроразгъване? Това изглежда връща формуляр, съдържащ макроса, който след това няма да бъде оценен, тъй като се връща като нормален код. - person DJD; 01.04.2014
comment
Да, кодът се преоценява и резултатът от macroexpand връща (* (+ 1 3) 2). Освен това използването на macroexpand-1 връща (user/streamops (+ 1 3) ((* :... 2))), както се очаква. - person juan.facorro; 01.04.2014