2009-12-01 7 views
8

実行時にfnを完全に生成したい(つまり、名前とargシンボルはコードではなく実行時に決定されます) これを達成する最も良い方法は何ですか?Clojure:実行時に関数を作成する方法

たとえば、次の機能を実装するにはどうすればよいですか?名前、引数と体が符号化されていない機能が、ランタイム

答えて

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

そして、いくつかの使用で決定することができ

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

注:このように使用されるだろう

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

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

ただし、私はこのアプローチが本当に好きではありません。それは本当に難しいにおいがあります:eval。なぜ実行時にグローバルを生成したいのですか?私は間違った名前空間や他の厄介な問題をさまざまな問題に抱えています...

+0

はい。これは醜いものです。私がこれを必要とするのは、ClojureのGeneticProgrammingを実験しているからです。 Clojureはこれに本当に自然なようです。 – GabiMe

+0

ああ。 OK。 GPは 'eval'を法的に使うことができます。しかし、 'eval'を使って奇妙な結果に気をつけてください。 – kotarak

+0

なぜeval?マクロでこれを行うことはできませんでしたか? –

0

私は確信していませんが、あなたはevalよりも優れたマクロでこれを行うことができると信じています。

(defmacro gen-fn 
    [n as b] 
    (let [n (symbol n) 
     as (vec (map symbol as))] 
    `(intern *ns* n (fn ~n ~as [email protected])))) 
+1

これは実行時には機能しません。ポイントは、事前に 'n'、' as'と 'b'を知る必要があることです。そして、あなたはできる:(defmacro gen-fn [n as b] '(defn ~(symbol n) ~(vec (map symbol as)) [email protected]))。 'eval'アプローチでは、' gen-fn'への引数は任意の計算の結果になる可能性があります。 – kotarak

1

もう一つの方法は、 "文字列を読み" "evalの" を使用している:

ユーザー=>(DEF F1(evalの(読み取り、文字列を "(FN [XY](* XY))") ))

# 'ユーザ/ F1

ユーザー=>(F1 3~5)

関連する問題