考虑以下代码
(defprotocol ICat "Foo"
(meow [cat]))
(defrecord Cat [a b] "Cat"
ICat
(meow [cat] (some-expensive-operation a b)))
有没有办法可以让某个地方进入那里?
在我执行时,我更愿意(一些昂贵的操作a b)被评估一次
(->Cat a b)
所以在(喵猫)时,它只返回预先缓存的值,而不是在运行中重新计算它。例如:
[1] (let [x (->Cat a b)]
[2] (meow x)
[3] (meow x)
[4] (meow x))
我希望(一些昂贵的操作)在[1]处被恰好评估一次,然后对于[2],[3],[4]它只返回旧值。
答案 0 :(得分: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)))
当你的代码变得更复杂时,我发现你经常想要在任何情况下定义你自己的构造函数。
请注意,您可能还需要考虑以延迟序列或延迟包装昂贵的操作,以便只在需要时才进行计算。
答案 1 :(得分:1)
如果你的功能是参考透明的,那么你可以将你的功能包裹在memoize
中。至少,您可以:
(def memo-some-expensive-function (memoize some-expensive-function))
然后在记录中使用memo-some-expensive-function
。
答案 2 :(得分:0)
我开始相信最简单的方法可能是
围绕defrecord创建一个包装器
这个包装器允许我指定我想要重新计算的其他字段
并将这些额外字段附加到“真正的”defrecord