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.

+4
source share
3 answers

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.

+3
source

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.

+1
source

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

0
source

Source: https://habr.com/ru/post/1414645/


All Articles