5

语境

考虑以下代码

(defprotocol ICat "Foo"
  (meow [cat]))

(defrecord Cat [a b] "Cat"
  ICat
  (meow [cat] (some-expensive-operation a b)))

问题

有没有办法我可以在某个地方放一个让?

我希望 (some-expensive-operation ab) 在我执行时只评估一次

(->Cat a b)

这样在 (meow cat) 的时候,它只是返回预缓存的值,而不是动态地重新计算它。例如:

[1] (let [x (->Cat a b)]
[2]   (meow x)
[3]   (meow x)
[4]   (meow x))

我希望(一些昂贵的操作)在 [1] 处被评估一次,然后对于 [2]、[3]、[4] 它只返回旧值。

4

3 回答 3

3

我建议包装逻辑以在构造函数中调用一次昂贵的操作,并将结果作为常规值存储在记录中:

(defprotocol ICat "Foo"
  (meow [cat]))

(defrecord Cat [a b] "Cat"
  ICat
  (meow [cat] (:meow cat)))

(defn make-cat [a b]
  (assoc (->Cat a b) :meow (some-expensive-operation a b)))

当您的代码变得更加复杂时,我发现您经常希望在任何情况下定义自己的构造函数。

请注意,您可能还需要考虑将昂贵的操作包装在惰性序列或延迟中,以便仅在需要时才计算它。

于 2012-05-28T02:20:20.353 回答
1

如果你的函数是引用透明的,那么你可以将你的函数包装在memoize. 至少,您可以:

(def memo-some-expensive-function (memoize some-expensive-function))

然后memo-some-expensive-function在你的记录中使用。

于 2012-05-27T23:16:48.113 回答
0

我开始相信解决这个问题的最简单方法可能是

  • 在 defrecord 周围创建一个包装器

  • 此包装器允许我指定要重新计算的其他字段

  • 并将这些额外字段附加到“真实”defrecord

于 2012-05-27T23:38:26.380 回答