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

然后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的seed函数中存在一个错误 https://clojure.atlassian.net/browse/CMEMOIZE-27
by
clojure.core.memoize 的主分支针对这个问题进行了修复:而不是将 derefable-seed 公开,我增加了一个新的 memoizer 函数,该函数接收一个函数、一个缓存(不是缓存工厂)和一个可选的种子/基础哈希表。这使得创建自定义缓存的函数变得更加容易,同时也减少了暴露库内部结构。

我会尽快发布带有此新功能的功能更新版本。
谢谢。我现在正在使用它 https://github.com/john-shaffer/krulak/blob/ba09b5098eff2f614ffe2b98c6ed5c6fb2783dc5/src/krulak.clj#L34
我还创建了几个其他函数,它们可以访问 memoize 内部结构。我基本上需要 memoize 相当于 core.cache 接口中的一切。对于添加到 core.memoize 有这样的计划吗?
我不太确定你在这里问什么 -- core.memoize 基于一个可插拔的 PluggableMemoization 类型,它实现了 core.cache 协议,因此具有所有相同的功能。你能具体说明你需要添加到 core.memoize 的具体内容吗?你觉得需要使用 core.memoize 的私有部分来扩展和定制缓存令我感到不舒服。你可以为库中你认为需要解决的问题创建一个新的问题线程。
我认为我对如何替换 PluggableMemoization 的方法不是很清楚。我可以访问 :clojure.core.memoize/cache 原子,但 cache-id 的私有性让我感觉原子位置可能是实现细节,可能会更改。依赖这个原子是否可以,还是我遗漏了其他东西?
by
您是说的类似这样的情况吗:[链接](https://github.com/clojure/core.memoize/blob/master/src/test/clojure/clojure/core/memoize_test.clj#L207-L217) 使用 memo-swap!(与快照结合用于访问当前缓存中的内容)?

如果不是,能否用一种我能明白的方式来解释您试图解决的问题,这样我就能看出您认为API缺少些什么?
by
memo-swap! 和 snapshot 结合使用没问题,但 snapshot 会在每次设置缓存中的特定值时创建一个新的 map,这对缓存设置操作来说开销太大。我将就这个问题打开一个新的帖子。我其他的用法在理解了 API 后能够很好地适配到 API 中。我也希望有权限用不同的参数替换缓存,而 snapshot 对此非常合适。
...