Question

I am trying to write a macro similar (I think) in function to the threading macro, however this would allow me to specify a keyword where the previous form's insertion would happen. I was planning on using clojure.walk/prewalk-replace, but I am getting a clojure.lang.ArityException. Here is the code:

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

but when I try to apply the unit test:

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

It produces:

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

What am I doing wrong?

Was it helpful?

Solution

You seem to have a misplaced syntax-quote ` in the definition of your macro, since it is placed at the end of it in the code you posted, but there's no syntax-quoting in the forms where you use unquote ~.

The following works just fine:

(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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top