请在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

由于缓存元素的可解引用性质是实现了细节,可能存在更好的扩展这种方式。

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

   (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
Contrib 项目通常使用 Maven 运行:mvn test

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

可选地提供用于 Clojure 版本的别名:clojure -A:test:runner:1.8

build-memoizer 目前如此通用是因为它需要能够支持任意缓存,这些缓存可以有任意顺序的任意参数(因此你的辅助函数只为某些缓存工作)。
by
在查看这个时,我意识到 PluggableMemoization 的 seed 函数存在一个错误 https://clojure.atlassian.net/browse/CMEMOIZE-27
clojure.core.memoize的master分支已经修复了这个问题:不是将derefable-seed设置为公共的,而是添加了一个新的memoizer函数,该函数接受一个函数、一个缓存(不是一个缓存工厂)和一个可选的种子/基本散列映射。这使得创建自定义缓存的函数更容易,同时减少了库内部结构的暴露。

我将在“不久”之后发布具有此更新功能的新版本。
谢谢。我现在在https://github.com/john-shaffer/krulak/blob/ba09b5098eff2f614ffe2b98c6ed5c6fb2783dc5/src/krulak.clj#L34使用这个。
我还创建了几个其他函数,它们深入到memoize内部。我基本上需要一个memoize操作符,以匹配core.cache接口中的所有功能。在core.memoize中添加类似的功能有价值吗?
我不太清楚你在这里问什么——core.memoize基于一个可插拔的memoization类型,该类型实现了core.cache协议,因此具有所有相同的功能。你能具体说明你觉得需要添加到core.memoize中的功能吗?你觉得需要使用core.memoize的私有部分来拓展和定制memoization让我感到不舒服。如果你觉得库中有哪些地方需要处理,请开始一个新的问题线程。
我觉得我对如何交换可插入的Memoization方式不太清楚。我可以访问: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!(与快照结合来访问当前缓存的值)?

如果不是的话,能否用我能理解的方式解释一下你试图解决的问题,以便我能看出你在API中认为遗漏了什么?
memo-swap! 结合快照是可行的,但快照每次都会创建一个新的带有缓存中所有项目的映射,这对设置缓存中特定值来说开销太大。我将为这个问题开一个新的帖。我其他的使用在了解API之后都能很好地适应API。我确实希望有在与不同参数交换缓存的能力,而快照对此非常完美。
...