On Oct 1, 3:59 am, Stefan Rohlfing <[email protected]> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
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