1

About a week ago I asked a question in this thread: Looping through a "let"-list in Clojure? I received a good answer however, a rather confusing question have arisen in my head:

Here's part of the answer:

(defmacro anaphoric-let [alternating-symbols-and-values & body]
    `(let [~@alternating-symbols-and-values
           names# (quote ~(flatten (partition 1 2 alternating-symbols-and-values)))
           values#  ~(vec (flatten (partition 1 2 alternating-symbols-and-values)))
           ~'locals (zipmap names# values#)]
        ~@body))


Input: 
(anaphoric-let [a 1 b 2 c 3 d 4 e "cat"] 
     (dorun (for [x (vals locals)] 
          (if (number? x) (println "roar")))))

The (dorun) statement in this case is the body in the macro parameter right? So I was under the impression that it would simply "copy-paste" the body. So instead of:

~@body

It would look like below then it would unquote the copied text and all that:

~@(dorun (for [x (vals locals)] 
       (if (number? x) (println "roar"))))

In my attempt to trying to interpret all of what's happening, I tried the exact thing I just explained. Instead of having ~@body I attempted to put some "real code" there.

It would then look like this:

(defmacro anaphoric-let [alternating-symbols-and-values & body]
     `(let [~@alternating-symbols-and-values
          names# (quote ~(flatten (partition 1 2 alternating-symbols-and-values)))
          values#  ~(vec (flatten (partition 1 2 alternating-symbols-and-values)))
          ~'locals (zipmap names# values#)]
       ~@(dorun (for [x (vals locals)] 
             if (number? x) (println "roar"))))))

And this does not work and complains that it's "Unable to resolve symbol: locals in this context" Me being such a newbie at this, I have tried experimenting and analyzing but I've gotten no wiser. Everytime I think I got it all figured out, there's always this little "but..." that comes along and crushes everything!

I feel as if I do have a decent understanding about the the rest of the example, except for the evil ~@body... My personal guess is that since I lack a full understanding of how to combine all these little quirky symbols, that I am probably missing some kind of combination of them...

1 Answer 1

1

~@expr inside a backquoted expression means evaluate expr and splice it into the surrounding expression.

Since you don't want to evaluate your (dorun ...) expression, you can just copy & paste it instead:

(defmacro anaphoric-let [alternating-symbols-and-values & body]
     `(let [~@alternating-symbols-and-values
          names# (quote ~(flatten (partition 1 2 alternating-symbols-and-values)))
          values#  ~(vec (flatten (partition 1 2 alternating-symbols-and-values)))
          locals# (zipmap names# values#)]
       (dorun (for [x (vals locals#)] 
           if (number? x) (println "roar"))))))

Since you don't need to insert specific symbols into the body anymore, I moved replaced locals with to a gensym'd symbol

Now why you'd ever want to introduce user-specified symbols in a hard-coded macro like this, I have no idea. I'm assuming this is just for experimentation.

Sign up to request clarification or add additional context in comments.

4 Comments

Hehe I actually tried with a simple copy and paste but since this is my first time dealing with the #, it seems that my mistake was not adding # in the for statement. And yes, I'm not aiming to achieve greatness or something, just merely playing around. You say it's a bad practice which I did not know about, I guess I am having a hard time really comprehending the differences between a macro and function, I keep trying to translate stuff into Java train of thoughts to try and understand it but I suppose it's not very wise to do that since this is not OOP...
HOWEVER!!! I tried the code above and now (anaphoric-let [a "cat" b 2]) isn't possible? "It's saying Wrong Number of args(4) passed"
That's ~probably~ because the (if ...) expression is broken. You were missing a ( before the if and I copied it like that, missing the error.
Thanks, this fixed error. There was another error after that, complaining about "x" but I replaced all the x's with x# and it seems to be functioning well now. Thanks, I totally gotta go read up on the '#' it seems though!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.