Clojure: defRecord, defProtocol: do expensive calculations only once
Context
Consider the following code snippet
(defprotocol ICat "Foo" (meow [cat])) (defrecord Cat [ab] "Cat" ICat (meow [cat] (some-expensive-operation ab)))
Question
Is there a way I can put somewhere there?
I would prefer that (some expensive operation ab) be evaluated exactly once, at runtime
(->Cat ab)
so that during (meow cat), he simply returns the previously cached value, and does not recount it on the fly. For example:
[1] (let [x (->Cat ab)] [2] (meow x) [3] (meow x) [4] (meow x))
I want (some expensive operation) to be evaluated exactly once in [1], then for [2], [3], [4] it just returns the old value.
I would suggest wrapping the logic to invoke an expensive operation once in the constructor function and save the result as a regular value in the record:
(defprotocol ICat "Foo" (meow [cat])) (defrecord Cat [ab] "Cat" ICat (meow [cat] (:meow cat))) (defn make-cat [ab] (assoc (->Cat ab) :meow (some-expensive-operation ab)))
As your code gets more complex, I find that you often want to define your own constructor functions anyway.
Please note that you can also consider moving an expensive operation to a lazy sequence or delay so that it can only be calculated if necessary.
If a function works transparently, you can wrap your function in memoize
. At a minimum, you could:
(def memo-some-expensive-function (memoize some-expensive-function))
and then use memo-some-expensive-function
in your entry.
I begin to believe that the easiest way it can be
create a wrapper around defrecord
this shell allows me to specify other fields that I want to recount
and attach these additional fields to the "real" defrecord