5

I have a function spec defined like this, and I want to evaluate it into a function object so I can pass around.

(def spec '(foo [n] (* 2 n)))

I can create a macro like this

(defmacro evspec [name arg & body] `(defn ~name [~arg] ~@body))

then the following call will give me function foo. when called with 3, (foo 3), will return 6.

(evspec foo n (* 2 n))

However, if I get the function body from my spec defined above, the function foo returned wont evaluate the body form (* 2 n), instead, it return the body form.

(let [foo (first spec) arg (first (second spec)) body (last spec)]
  (evspec foo arg body))

user=> (foo 3)
(* 2 n)

I notice the foo function created now is $eval$foo

user=> foo
#<user$eval766$foo__767 user$eval766$foo__767@39263b07>

while the working foo function is

user=> foo
#<user$foo user$foo@66cf7fda>

can anybody explain why is the difference and how can I make it work ? I want to have a way without replying on eval ? coming from javascript background, somehow I always think eval is evil.

1
  • If you want to pass a function object around, simply use (defn foo [...) and pass the symbol foo around. Commented Jul 10, 2013 at 11:35

1 Answer 1

6

It's simply not possible to do it in general without eval. A macro is simply a function which is passed its argument expressions literally at compile time (when it is in general fundamentally impossible to know what their values might be at runtime). In particular, in the call to evspec inside the let form in the question text, where the return value is (* 2 n), the evspec macro expander sees literally the symbol foo and the symbol n as its positional arguments and (body) (a seq containing the single symbol body) as its "rest" argument; the return value is in line with these inputs.

However, using eval for this sort of purpose is perfectly fine. It's important to keep in mind that it has a considerable runtime cost, so you'll want to use it somewhat sparingly, but once you produce a function using eval, it is a perfectly good Clojure function, just as fast as any other.

Also, note that while in JavaScript eval operates on text, Clojure's eval operates on Clojure data structures -- indeed the same data structures macros operate on -- which arguably makes it less error prone.

1
  • 1
    +1 for clojure eval on data structure while js eval on text !
    – haijin
    Commented Jul 11, 2013 at 4:36

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.