7

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

3 Answers 3

12
(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...

Sign up to request clarification or add additional context in comments.

6 Comments

Yes. This is ugly stuff. The reason I need this is I am experimenting with GeneticProgramming under Clojure. Clojure seems really natural for this.
Ah. Ok. GP may be a legal use of eval. But still stay alert for strange effects with eval.
why eval? couldn't you do this with a macro?
No, macros run at compile time, not at runtime.
Great answer. I'd just add that if the purpose if genetic programming then it might make sense to store the generated functions directly in a map rather than add them to a namespace (which could get confusing as it's a big chunk of mutable state...)
|
1

Another way is using "eval" and "read-string":

user=> (def f1 (eval (read-string "(fn [x y] (* x y))")))

#'user/f1

user=> (f1 3 5)

15

Comments

0

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

1 Comment

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.

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.