Does memoize
keep track of changes to binding which may make returning a computation it has stored incorrect?
For example if I have a function foo such as:
(defn foo [bar baz]
...
(let [config-val *config-val*]
...)
)
which I contain within a binding so I can change the value of *config-val*
, does memoizing it mean that if I change the value of *config-val*
, but not the parameters to it that it will not recompute the value of the function? Instead it will give me the value of the function with the old configuration?
In Clojure 1.3.0 memoize
doesn't keep track of rebinding.
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
Additionally,
user=> (binding [*x* 7] (f 3))
10
user=> (f 3)
10
user=> *x*
5
memoize
does not account for binding, this can be confirmed by looking at the source where the map in the atom is keyed only by the arguments. Indeed a function with dynamic rebinding is not "referentially transparent" (i.e. it cannot be replaced with its value).
Is there something that prevents you from passing the *config-val*
as an argument, at least to the function you wish to memoize?
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)))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With