2011-12-09 12 views
4

memoizeは、バインディングの変更を追跡していますが、それは正しく保存された計算を返す可能性がありますか?例えばmemoizeはClojureでのバインドとどのように対話しますか?

は、Iのような関数fooを持っている場合:私は、私は*config-val*の値を変更することができる結合内含む

(defn foo [bar baz] 
... 
    (let [config-val *config-val*] 
    ...) 
) 

はそれが意味memoizingないIが*config-val*の値を変更した場合、関数の値を再計算しないというパラメータはありませんか?代わりに、それは私に古い構成の関数の価値を与えるでしょうか?

答えて

4

In Clojure 1.3.0 memoizeでは、再バインドを追跡しません。

user=> (def ^:dynamic *x* 5) 
#'user/*x* 
user=> (def f (memoize #(+ *x* %))) 
#'user/f 
user=> (f 1) 
6 
user=> (binding [*x* 6] (f 1)) 
6 
user=> (binding [*x* 7] (f 1)) 
6 

また、

user=> (binding [*x* 7] (f 3)) 
10 
user=> (f 3) 
10 
user=> *x* 
5 
2

memoizeが、これは原子のマップは、引数だけでキーが付いてソースを調べることで確認することができ、結合を考慮していません。実際、動的再バインディングを有する関数は、「参照的に透明」ではない(すなわち、その値で置き換えることはできない)。

少なくとも、メモしたい機能には、*config-val*を引数として渡すことを防ぐ何かがありますか?


user=> (source memoize) 
(defn memoize 
    "Returns a memoized version of a referentially transparent function. The 
    memoized version of the function keeps a cache of the mapping from arguments 
    to results and, when calls with the same arguments are repeated often, has 
    higher performance at the expense of higher memory use." 
    {:added "1.0"} 
    [f] 
    (let [mem (atom {})] 
    (fn [& args] 
     (if-let [e (find @mem args)] 
     (val e) 
     (let [ret (apply f args)] 
      (swap! mem assoc args ret) 
      ret))))) 
+0

実際には、これを再構成する方法を試してみることにしました。いいコードを手に入れました。もっと速くする方法を考えようとしています。 – toofarsideways

2

documentation for memoizeが示すように、メモ化関数が結果に引数マッピングの内部キャッシュを維持します。 memoized関数が引数を指定して呼び出されると、すでに見たように、キャッシュから正しい戻り値を検索します。何も再計算されず、最後に関数を呼び出したときと同じ結果になります。すべての再バインドは無視されます。

user=> (def ^:dynamic op +) 
user=> (defn add [x y] (op x y)) 
user=> (add 1 2) 
3 
user=> (binding [op -] 
     (add 1 2)) 
-1 
user=> (alter-var-root #'add memoize) 
user=> (add 1 2) 
3 
user=> (binding [op -] 
     (add 1 2)) 
3 
関連する問題