memoize如何与Clojure中的绑定进行交互?

时间:2011-12-09 16:09:25

标签: performance clojure

memoize是否跟踪绑定的更改,这可能会导致返回存储不正确的计算?

例如,如果我有一个函数foo,如:

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

我在一个绑定中包含所以我可以更改*config-val*的值,记住它意味着如果我更改*config-val*的值,而不是它的参数,它将不会重新计算功能的价值?相反,它会给我带有旧配置的函数值?

3 个答案:

答案 0 :(得分:4)

在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

答案 1 :(得分: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)))))

答案 2 :(得分:2)

正如documentation for memoize建议的那样,memoized函数将保持参数的内部缓存映射到结果。当使用参数调用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