On Oct 1, 3:59 am, Stefan Rohlfing <stefan.rohlf...@gmail.com> wrote: > I wanted to expand the 'infix' macro presented in chapter 7.3.1 of > 'Clojure in Action' to handle nested s-expressions: > > My first version did not work: > > (defmacro my-infix [expr] > (if (coll? expr) > (let [ [left op right] expr] > (list op (my-infix left) (my-infix right))) > expr)) > > ;; Test: > (my-infix ((3 * 5) - (1 + 1))) > > ;; Wrong number of args (1) passed to: user$my-infix > ;; [Thrown class java.lang.IllegalArgumentException] > > I would love to know why the first version 'my-infix' throws an > exception. Can anybody give me a hint? I hope the answer could give me > a better understanding of how macros work.
I think I can explain - someone correct me if I'm wrong. The problem occurs while my-infix is being compiled. As the compiler works its way into the body of my-infix, it comes across a call to something called my-infix. Intuitively, you would expect that since my- infix is a macro (or is it? more to come), the compiler would call it then-and-there - but how could it? my-infix hasn't even finished compiling, so how could it possibly be called? So my next thought is that it should be an error - and this may very well be true. But it seems that what actually happens is that the my- infix var is in a sort of intermediate state - it exists, which is why the compiler doesn't complain, but it has not yet been flagged as being a macro. Try this: (defmacro ct-prn [expr] ; compile-time prn (prn (eval expr)) expr) (defmacro my-infix [expr] (ct-prn (meta #'my-infix)) (if (coll? expr) (let [ [left op right] expr] (list op (my-infix left) (my-infix right))) expr)) (prn (meta #'my-infix)) Here's what I get printed out: {:ns #<Namespace user>, :name my-infix} {:macro true, :ns #<Namespace user>, :name my-infix, :file "C:\\Temp\ \temp.clj", :line 5, :arglists ([expr])} So while compiling, my-infix is not yet flagged as a macro, so the call to it gets compliled into a regular, run-time call to a function. Still this seems like it should be OK - what's up with the "Wrong number of args (1)..." stuff? Isn't 1 the right number of args for my- infix? Actually, it's not. That's becuase the compiler inserts a couple of extra implicit arguments to all calls to macros. So in fact, my-infix, at runtime, expects 3 arguments. Check this out: user=> (defmacro foo [x] x) #'user/foo user=> (foo 23) 23 user=> (def foo2 (var-get #'foo)) #'user/foo2 user=> (foo2 23) java.lang.IllegalArgumentException: Wrong number of args (1) passed to: user$foo (NO_SOURCE_FILE:0) user=> (foo2 23 34 45) 45 I hope that makes it clearer. I certainly feel like I understand macros a little better after figuring this out. As for what exactly the two implicit args to macros are - I don't know. Someone else will have to explain that. - Chris -- 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 Note that posts from new members are moderated - please be patient with your first post. 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