Как memoize взаимодействует с привязкой в ​​Clojure? - PullRequest
4 голосов
/ 09 декабря 2011

Отслеживает ли memoize изменения в привязке, которые могут привести к неправильному возвращению сохраненного вычисления?

Например, если у меня есть функция foo, такая как:

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

который я включаю в привязку, чтобы я мог изменить значение *config-val*, означает ли это, что если я изменю значение *config-val*, а не параметры, то оно не пересчитает значение функции?Вместо этого он даст мне значение функции со старой конфигурацией?

Ответы [ 3 ]

4 голосов
/ 09 декабря 2011

В 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 голосов
/ 09 декабря 2011

Как следует из документации для 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
2 голосов
/ 09 декабря 2011

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)))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...