Рекурсивный макрос 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

Что я делаю неправильно?

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
Другие вопросы по тегам