How does memoize interact with binding in Clojure?

Does memoize changes in the binding, which can lead to the return of its incorrect calculation?

For example, if I have a foo function, for example:

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

which I contained in the binding, so I can change the value of *config-val* , does memoizing mean that if I change the value of *config-val* , but not the parameters, so that it does not recalculate the value to function? Instead, it will give me the value of the function with the old configuration?

+4
source share
3 answers

Clojure 1.3.0 memoize does not track recovery.

 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 

Besides,

 user=> (binding [*x* 7] (f 3)) 10 user=> (f 3) 10 user=> *x* 5 
+4
source

memoize does not take into account the binding, this can be confirmed by looking at the source, where the map in the atom is entered only by arguments. Indeed, a function with dynamic reordering is not “referentially transparent” (that is, it cannot be replaced by its value).

Is there something that is stopping you from passing *config-val* as an argument to at least the function you want to keep in memory?

 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
source

As the memoize documentation shows, a memoized function will save an internal cache of arguments matching results. When the memoized function is called with arguments, it has already seen that it will do nothing but find the correct return value from the cache. Nothing will be recounted, and you will get the same result as the last time you called the function. Any recreation will be ignored.

 user=> (def ^:dynamic op +) user=> (defn add [xy] (op xy)) 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 
+2
source

Source: https://habr.com/ru/post/1385558/


All Articles