memoize
是否跟踪绑定的更改,这可能会导致返回存储不正确的计算?
例如,如果我有一个函数foo,如:
(defn foo [bar baz]
...
(let [config-val *config-val*]
...)
)
我在一个绑定中包含所以我可以更改*config-val*
的值,记住它意味着如果我更改*config-val*
的值,而不是它的参数,它将不会重新计算功能的价值?相反,它会给我带有旧配置的函数值?
答案 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