On Jan 1, 2009, at 5:45 AM, synphonix wrote:

>
> Hello and happy new year,
>
> I've started this year with playing around with clojure macros and
> wrote a  macro that
> behaves in a way I don't understand:
>
> (defmacro foo
>  ([x] `(list ~x ~x))
>  ([x n] (if (<= n 0)
>           `(foo ~x)
>           `(foo ~(foo x)
>                 ~(- n 1)))))
>
> (foo :a 0) => (:a :a) ;; What I expected
> (foo :a 1) => nil ;; Here I would expect (foo (foo :a) 0)  => (foo
> (list :a :a) 0) => '((:a :a) (:a :a))
> (foo :a 2) => java.lang.NullPointerException
>
> Could someone please explain where my understanding of clojure macros
> is flawed ?
>

Yes, as is so often the case, macroexpand(-1) can illuminate:

Your problem is that when you say ~(foo x) you are running the macro  
during its own definition, rather than expanding into a call to itself:

(macroexpand-1 '(foo :a 1))
-> (user/foo (:a :a) 0) ;oops

What you want instead is to emit a call to the same macro in the  
expansion, ~(foo x) changed to (foo ~x):

(defmacro foo
  ([x] `(list ~x ~x))
  ([x n] (if (<= n 0)
           `(foo ~x)
           `(foo (foo ~x)
                 ~(- n 1)))))

(macroexpand-1 '(foo :a 1))
-> (user/foo (user/foo :a) 0)

(macroexpand '(foo :a 1))
-> (clojure.core/list (user/foo :a) (user/foo :a))

(foo :a 1)
-> ((:a :a) (:a :a))

(foo :a 2)
-> (((:a :a) (:a :a)) ((:a :a) (:a :a)))

Rich

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to