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

可能有一种更好的方法来提供这种类型的扩展,因为缓存元素可 deref 的这一事实被认为是实现细节。

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

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

记忆(memo)实现因此变成(除去文档)

   (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的主分支解决了这个问题:不是将derefable-seed公开,而是添加了一个新的memoizer函数,它接受一个函数、一个缓存(不是一个缓存工厂)和一个可选的种子/基本哈希表。这使得创建自定义缓存的函数更简单,同时减少了对外开放库的内部细节。

我将很快发布一个包含此功能更新的新版本。
by
谢谢。我现在在[https://github.com/john-shaffer/krulak/blob/ba09b5098eff2f614ffe2b98c6ed5c6fb2783dc5/src/krulak.clj#L34](https://github.com/john-shaffer/krulak/blob/ba09b5098eff2f614ffe2b98c6ed5c6fb2783dc5/src/krulak.clj#L34)使用它。
我还创建了几个其他函数,它们深入到memoize的内部。我基本上需要core.cache接口中所有内容的memoize等价物。有没有像这样的计划添加到core.memoize中?
by
我不知道你在问什么——core.memoize基于一个实现了core.cache协议的PluggableMemoization类型,所以所有相同的功能都存在。你能具体说明你觉得还需要添加到core.memoize中的内容吗?你觉得core.memoize的私有部分需要被用来扩展和定制memoization这一点让我感到不舒服。请自由为库中你认为需要解决的问题开始新的问题线程。
by
我想我并不清楚替换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! 和 snapshot 可以一起使用,但是 snapshot 在每次设置缓存中的特定值时都会创建一个新的映射,这对于缓存设置来说开销太大。我将为这个问题创建一个新的帖子。我的其他用途在与更好地了解 API 之后适合 API。我确实想要能够用不同的参数来交换缓存,而 snapshot 对于这个功能来说非常完美。
...