Clojure: defRecord, defProtocol: 只做一次昂贵的计算

5 clojure

语境

考虑下面的一段代码

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

(defrecord Cat [a b] "Cat"
  ICat
  (meow [cat] (some-expensive-operation a b)))
Run Code Online (Sandbox Code Playgroud)

有什么办法可以让我在某个地方扔东西吗?

我希望(一些昂贵的操作 ab)在我执行时只评估一次

(->Cat a b)
Run Code Online (Sandbox Code Playgroud)

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

[1] (let [x (->Cat a b)]
[2]   (meow x)
[3]   (meow x)
[4]   (meow x))
Run Code Online (Sandbox Code Playgroud)

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

mik*_*era 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)))
Run Code Online (Sandbox Code Playgroud)

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

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