1
votes

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

1 Answers

1
votes

~@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.