2024年Clojure状态调查!中分享您的想法。

欢迎!请查阅关于页面以获取有关此工具的更多信息。

+1
core.memoize

虽然可以使用memo-clear!强制刷新,但我们出于效率考虑进行了缓存,因此提供一个手动设置缓存值的方法会不错。这就是实现它的方法之一

(defn memo-miss!
  "Reaches into a core.memo-populated function and sets the cached value
  for a given seq of function args."
  [f args result]
  (when-let [cache (cache-id f)]
    (swap! cache clojure.core.cache/miss args (delay result))))

(testing "that setting cache values works as expected"
  (is (memo-clear! id))
  (is (memo-miss! id [29] :x))
  (is (= :x (id 29)))
  (is (= 42 (id 42))))

遵循现有的代码风格,可以这样写

(defn memo-miss!
  "Reaches into a core.memo-populated function and sets the cached value
  for a given seq of function args."
  [f args result]
  (when-let [cache (cache-id f)]
    (swap! cache
           (constantly (clojure.core.cache/miss @cache args (delay result))))))

我不明白为什么swap!... постоянно更受欢迎,或者它与reset!有何不同,但我也没有维护者数十年的经验!

2 个回答

+2

已选中
 
最佳答案

这是一个添加类似于“memo-swap!”函数的好理由

https://clojure.atlassian.net/browse/CMEMOIZE-9

正如该问题所述,clear “memo-swap!”的命名不佳,因为它实际上是“memo-reset!”。向后兼容性意味着我无法重命名它,但我可以添加memo-reset!,并引入新的arity参数的memo-swap!,它实际上会按您希望的方式运行

(memo/memo-swap! f assoc args result)

这将保持实现封装,并提供您想要的语义。

关于使用swap! 而非reset!的样式问题,我不确定为什么那样写。我会看看能否弄清楚并给你回复。

现在大师已经实现了这个更改(memo-swap!的一个额外的量级)

(memo/memo-swap! f cache/miss args result)

它还添加了memo-reset!,具有memo-swap!的原始行为(并弃用了memo-swap!的2方重版本)。
这真的很聪明。我以为没有一种方法可以在不依赖于延迟实现细节的情况下添加一个通用的“swap! cache-protocol-fn”函数,但当然只有miss使用了3个参数。这是一个绝妙的解决方案。
0投票

我同意,使用constantly忽略了传入的cache原子(函数重试时可能改变)的值,这使其与reset!相同,意味着memo-miss!在那里引入了竞争条件。

然而,我认为这是多层原子的作用。出于某种奇妙的原因,core.cache和core.memoize是不同的库,core.cache试图将缓存作为不可变事物呈现,而memoize通过在原子里存储缓存来添加可变性。但是随着开发进行,已经变得明显,‘不可变的’缓存需要一些可变性,因此它们现在内部有自己的原子。所以memoize代码现在似乎基本上忽略了memoize原子。

我认为这使其变得安全,即使看起来很丑陋。

clojure.core.cache 仍然是以不可变的形式存在。clojure.core.cache.wrapped 是最近添加的,提供了 API 的 atom 包装版本,因为这是人们主要使用的方式。clojure.core.memoize 一直将 clojure.core.cache(不可变)缓存包装在一个 atom 中,并存储在 memoized 函数的元数据中 - 但它还实现了 clojure.core.cache 协议,就好像它也是一个不可变缓存... 这既是有些令人困惑,实际上也很难正确使用。

作为一种折衷,clojure.core.memoize 也一直有两个在 atom 上操作但不像完整 API 那样公开的功能... 这也使得一些操作比必要的更复杂。

我认为,大多数情况下,clojure.core.memoize 的用户不倾向于手动修改缓存的函数结果,因此这个用例从未被报告为需求(直到最近 John 的帖子),所以这个库的这一部分一直是冷寂缺乏关注。
...