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

Reply via email to