Andreas Kostler <andreas.koest...@leica-geosystems.com> writes:

> Is this a 'bug' with eval?

No, eval is a simply a function and so like any other function it can't
"see" the lexical (local) environment which it was called from.

Doing this:

    (let [a 1, b 2] (eval '(+ a b)))

Is similar to doing this:

    (defn cake []
      (+ a b))

    (let [a 1, b 2] (cake))

Anyway, here's my take on a eval macro which captures the lexical
environment.  It's similar to Ken's but avoids the need to explicitly
specify the environment.

First we need a version of eval which takes some let bindings.  This is
straightforward, just wrap the form in a let statement:

    (defn eval-let [bindings form]
      (eval `(let [...@bindings] ~form)))

Note that's just a regular function again.  We can use it like so:

    (eval-let '[a 1, b 2] '(+ a b))
    ;; => 3

Next we need a way of getting at the lexical environment.  Since 1.2
there's a nice supported way to do it.  There's an implicit argument
passed to macros called &env.  (keys &env) will get us a list of symbols
in the lexical environment, so:

    (defmacro lexical-bindings []
      (let [symbols        (keys &env)
            quoted-symbols (for [sym symbols] `(quote ~sym))]
        (vec (interleave quoted-symbols symbols))))

What the heck does that do?  Simple, if the environment contains
bindings 'a and 'b then it expands to the code ['a a 'b b].

Let's try it:

    (let [a 1, b 2] (lexical-bindings))
    ;; => [b 2 a 1]

Perfect!  That's actually all we need:

    (let [a 1, b 2] (eval-let (lexical-bindings) '(+ a b)))
    ;; => 3

But for brevity we could define one last macro:

    (defmacro lexeval [form]
      `(eval-let (lexical-bindings) ~form))

And thus a version of eval which does what you're expecting:

    (let [a 1, b 2] (lexeval '(+ a b)))
    ;; => 3

-- 
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