分享您的想法,参与2024 Clojure状态调查!

欢迎!请参阅关于页面,了解此工作的更多信息。

0
core.memoize

用例:我有一段代码效果很好

(require '[clojure.core.cache :as cache])
(require '[clojure.core.memoize :as memo])
(import 'clojure.core.memoize.PluggableMemoization)

(defn lru-ttl-cache [base threshold ttl]
  (-> base
      (cache/lru-cache-factory :threshold threshold)
      (cache/ttl-cache-factory :ttl ttl)))

(defn lru-ttl-memo
  ([f base threshold ttl]
   (memo/build-memoizer
      #(PluggableMemoization. %1 (lru-ttl-cache %4 %2 %3))
      f
      threshold
      ttl
      (@#'memo/derefable-seed base))))

但它依赖于一个私有变量。这应该真正是公开的,这样客户就可以更容易地提供他们自己的实现。

顺便说一下,这是非常好的库。我喜欢在Clojure生态系统工作。

1 条回答

+1

编辑
 
最佳答案

已创建JIRA问题: https://clojure.atlassian.net/browse/CMEMOIZE-28

出于某种原因,可能存在一种更好的方法来实现这种扩展,因为缓存元素可悬停是作为实现细节

这可能与一个很好的主意。我编写了一个辅助函数来抽象掉细节

   (defn build-helper [cache-factory f base & args]
     (build-memoizer
      #(PluggableMemoization. %1 (apply cache-factory %2 %3))
      f
      (derefable-seed base)
      args))

之后的记忆实现在没有文档的情况下成为(

   (defn memo
     ([f] (memo f {}))
     ([f seed]
      (build-helper cache/basic-cache-factory f seed)))

我的早期 lru-ttl-memo 函数简化为

   (def lru-ttl-memo
     (partial memo/build-helper lru-ttl-cache))

这确实大大简化了,并且与实现细节无关。

差异在https://github.com/john-shaffer/core.memoize/commit/669febe3af7f325de43cab82ab7d09469fd148a1

我真的不知道你通常是如何运行测试的。我必须将代码符号链接到一个leiningen项目中,热修补它,然后调用clojure.test/run-tests。
by
贡献项目通常使用Maven运行:mvn test

我维护的所有贡献项目也支持CLI/deps.edn,你可以使用以下命令运行这些测试:clojure -A:test:runner

可选地提供一个版本别名以使用Clojure版本:clojure -A:test:runner:1.8

现在build-memoizer之所以如此通用,是因为它需要能够支持任意的缓存,这些缓存可以以任意的顺序具有任意的参数(因此你的辅助程序只为一些缓存工作)。
by
在查看这个时,我意识到PluggableMemoization的种子函数中有一个错误https://clojure.atlassian.net/browse/CMEMOIZE-27
by
clojure.core.memoize的master分支为此错误提供了修复:而不是将derefable-seed公开,我添加了一个新的记忆函数,它接受一个函数、一个缓存(而不是缓存生成器)和一个可选的种子/基本哈希表。这使得创建自定义缓存函数更容易,同时展示了更少的库内部结构。

我将很快推出一个带有这项更新功能的新版本。
谢谢。我现在正在使用这个功能在https://github.com/john-shaffer/krulak/blob/ba09b5098eff2f614ffe2b98c6ed5c6fb2783dc5/src/krulak.clj#L34
我还创建了几种其他能够深入到memoize内部的函数。我基本上需要core.cache接口中的所有内容的memoize等价函数。您是否考虑过在core.memoize中添加类似的功能?
我不太清楚您在这里要求什么 —— core.memoize是基于一个实现了core.cache协议的可插拔memoization类型,所以所有相同的功能都是现成的。您能具体说明您觉得还需要添加到core.memoize中的内容吗?您觉得core.memoize的私有部分需要用于扩展和定制memoization,这让我有些不舒服。您可以为每个需要解决库的某个部分自由地开启新的问题线程。
我想我不是很清楚支持在PluggableMemoization中替换的方式。我可以访问:clojure.core.memoize/cache原子,但由于cache-id是私有的,给我的印象是原子的位置可能是实现细节,可能会发生变化。是否可以依赖这个原子,还是我遗漏了什么?
您是指这样的内容吗?https://github.com/clojure/core.memoize/blob/master/src/test/clojure/clojure/core/memoize_test.clj#L207-L217 使用memo-swap!(结合snapshot访问当前缓存中的内容)?

如果不可以,你能用让我能看到你在API中认为缺失的地方的方式来解释你试图解决的问题吗?
memo-swap! 加上快照功能是可行的,但是快照会在缓存中每个项目都创建一个新的映射,这对于设置缓存中的特定值来说过于奢侈。我将为这个问题开一个新的主题。我的其他用途在更好地理解了API之后也很好地融入了API中。我确实想要有能力以不同的参数交换缓存,而快照对此非常合适。
...