In clojure, how to make code template when implementing a macro with recursion

I am trying to implement a macro to recursively convert an infix list to a prefix. I ran into a problem as follows:

;;this works (defmacro recursive-infix [form] (list (second form) (first form) (if (not (seq? (nth form 2))) (nth form 2) (recursive-infix (nth form 2))))) ;;this doesn't work (defmacro my-recursive-infix [form] `(~(second form) ~(first form) (if (not (seq? ~(nth form 2))) ~(nth form 2) (my-recursive-infix ~(nth form 2))))) (macroexpand '(recursive-infix (10 + 10))) ;;get (+ 10 10) (macroexpand '(my-recursive-infix (10 + 10))) ;;get (+ 10 (if (clojure.core/not (clojure.core/seq? 10)) 10 (user/my-recursive-infix 10))) (recursive-infix (10 + 10)) ;;get 20 (my-recursive-infix (10 + 10)) ;;Don't know how to create ISeq from: java.lang.Integer [Thrown class java.lang.IllegalArgumentException] 

Where is the problem? How to define a macro with a code template?

PS I changed the code to this and it works, why? what is the difference?:

 (defmacro my-recursive-infix [form] (if (not (seq? (nth form 2))) `(~(second form) ~(first form) ~(nth form 2)) `(~(second form) ~(first form) (my-recursive-infix (nth form 2))))) 
+6
source share
1 answer

In the original version, verification (if (not ...)) occurred at compile time; you included it in the extended code instead. So, here is the minimal change that will make it act the way you want - itโ€™s actually the same as the original, but it โ€œflipsโ€ what is quoted and what is not.

  (defmacro my-recursive-infix [form] (let [third (nth form 2)] `(~(second form) ~(first form) ~(if (not (seq? third)) third `(my-recursive-infix ~third))))) 

However, it is slightly better to use destructuring to pull out fragments of the form ahead of time, and not in place:

 (defmacro my-recursive-infix [form] (let [[x op y] form] `(~op ~x ~(if (not (seq? y)) y `(my-recursive-infix ~y))))) 

And even better - move the non-recursive case outside so that (a) it works for alphabetic numbers and (b) the code is more like expanding:

 (defmacro my-recursive-infix [form] (if-not (seq? form) form (let [[x op y] form] `(~op ~x (my-recursive-infix ~y))))) 
+13
source

Source: https://habr.com/ru/post/904423/


All Articles