On Nov 13, 8:36 am, Stuart Halloway <[EMAIL PROTECTED]> wrote:
> Hi Meikel,
>
> I spent a few minutes trying to write a macro to do this that doesn't
> use eval. So far no good. Is it truly impossible, though? I have never
> seen a good discussion of "things that can be done only with eval".
> Any pointers?
>

The admonitions against eval are important, because people frequently
get confused about macros, compile time, runtime etc. 99.9% of the
time, especially when you are starting out, you shouldn't be using
eval.

The purpose of a macro is to transform a form into another form on
behalf of the compiler. That's all!

The fact that CL and Clojure macros can run arbitrary code makes them
powerful, but doesn't change that fundamental purpose. People see them
and think - oh, this is just a function that doesn't evaluate its
arguments, and start writing macros for their runtime values, or worse
yet, their effects. That's wrong!

People often think they need runtime code generation without thinking
it all the way through - if you write something that generates code at
runtime, especially new names, how can the other code that you wrote
prior to runtime use it?

Macros allow you to do dynamic code generation that is accessible to
other code prior to runtime.

Is there ever a reason to generate code at runtime? Sure - to write a
repl, or an interpreter.

Of course, I've overstated everything, but it's only because, until
you've developed an understanding of the above, you shouldn't be
trying anything trickier.

That said, and I'm loath to show this, the original example begs the
conflation of compile and runtime. Here's how to do it without eval:

;;;;; gross - please don't write code like this!!!

(def bindings-list '[one 1])

(defmacro list-let
  "a horrible macro that expects to be passed the name of a global var
that contains a binding list"
  [bs & body]
  (let [blist (var-get (resolve bs))]
    `(let ~blist [EMAIL PROTECTED])))

(macroexpand-1 '(list-let bindings-list one))
-> (clojure.core/let [one 1] one)

(list-let bindings-list one)
-> 1

list-let is passed the name of a var that it needs to resolve at
compile time. It does so, gets its value, then inserts that form into
its expansion. The problem is, people may write things like this and
expect the expansion to use the runtime value of bs at each expansion
point - not so.

The purpose of a macro is to transform a form into another form on
behalf of the compiler. That's all!

Rich

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to