How to convert a list form into a function in clojure
clojure
Solution
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.
Problem
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.