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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---