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