views:

163

answers:

2

I want to generate a fn totally at runtime (i.e. the name and the arg symbols are decided at runtime, not in code) What's the best way to achieve this ?

For example how can I implement the following function ?

(defn gen-fn [name arg-symbols body]
...
...

which would be used like this:

(gen-fn "my-func-name" (symbol "x") (symbol "y") (println "this is body. x=" x))

Note that function name, the args and the body are not coded but can be decided at runtime

+9  A: 
(defn gen-fn
  [n as b]
  (let [n        (symbol n)
        as       (vec (map symbol as))
        fn-value (eval `(fn ~n ~as ~b))]
    (intern *ns* n fn-value)))

And some use:

user=> (gen-fn "foo" ["x"] '(do (println x) (println (inc x))))
#'user/foo
user=> (foo 5)
5
6
nil

However, I don't really like this approach. It smells really hard: eval. Why do you want to generate globals at runtime? I see various problems with wrong namespaces and other ugly hiccups rising at the horizon...

kotarak
Yes. This is ugly stuff. The reason I need this is I am experimenting with GeneticProgramming under Clojure. Clojure seems really natural for this.
bugspy.net
Ah. Ok. GP may be a legal use of `eval`. But still stay alert for strange effects with `eval`.
kotarak
why eval? couldn't you do this with a macro?
Jeremy Wall
No, macros run at compile time, not at runtime.
Dan
A: 

I'm not entirely sure but I believe you could do this with a macro which would be superior to eval.

(defmacro gen-fn
  [n as b]
  (let [n  (symbol n)
        as (vec (map symbol as))]
    `(intern *ns* n (fn ~n ~as ~@b))))
Jeremy Wall
This does not work at runtime. The point is: you need to know `n`, `as` and `b` in advance. And then you can do: <code>(defmacro gen-fn [n as b] `(defn ~(symbol n) ~(vec (map symbol as)) ~@b))</code>. With the `eval`-approach the arguments to `gen-fn` can be results of arbitrary computations.
kotarak