OParry
OParry

Reputation: 317

Memoize over one parameter

I have a function which takes two inputs which I would like to memoize. The output of the function only depends on the value of the first input, the value of the second input has no functional effect on the outcome (but it may affect how long it takes to finish). Since I don't want the second parameter to affect the memoization I cannot use memoize. Is there an idiomatic way to do this or will I just have to implement the memoization myself?

Upvotes: 1

Views: 702

Answers (5)

Aneesh
Aneesh

Reputation: 1

You can use a custom memoize function. For example
(defn memoize-first [f]
(let [cache (atom {})]
(fn [x]
(if-let [cached-result (get @cache x)]
cached-result
(let [result (f x)]
(swap! cache assoc result)
result))))
(defn your-function []
;;
)

(def memoized-function (memoize-first your-function))

Upvotes: 0

Kaleb Roncatti
Kaleb Roncatti

Reputation: 43

Maybe you are not able to natively memoize those two arguments, but you could use partial instead to take fewer than the normal arguments to your function. You won't be caching it's execution but that may be helpful if you need to pre-load some function parameters:

An example:

(defn sum [a b]
   (+ a b))

(def partial-sum (partial sum 2))
(partial-sum 3) ;; returns 5

Upvotes: 0

Michiel Borkent
Michiel Borkent

Reputation: 34800

memoize doesn't support caching only on some args, but's pretty easy to make it yourself:

(defn search* [a b]
  (* a b))

(def search
  (let [mem (atom {})]
    (fn [a b]
      (or (when-let [cached (get @mem a)]
            (println "retrieved from cache")
            cached)
          (let [ret (search* a b)]
            (println "storing in cache")
            (swap! mem assoc a ret)
            ret)))))

Upvotes: 2

Taylor Wood
Taylor Wood

Reputation: 16194

I'd recommend using a cache (like clojure.core.cache) for this instead of function memoization:

(defonce result-cache
  (atom (cache/fifo-cache-factory {})))

(defn expensive-fun [n s]
  (println "Sleeping" s)
  (Thread/sleep s)
  (* n n))

(defn cached-fun [n s]
  (cache/lookup
    (swap! result-cache
           #(cache/through
              (fn [k] (expensive-fun k s))
              %
              n))
    n))

(cached-fun 111 500)
Sleeping 500
=> 12321
(cached-fun 111 600) ;; returns immediately regardless of 2nd arg
=> 12321
(cached-fun 123 600)
Sleeping 600
=> 15129

Upvotes: 2

You can wrap you function into another function (with one parameter) and call it the function with second default parameter. Then you can memoize the new function.

(defn foo
  [param1]
  (baz param1 default-value))

Upvotes: 0

Related Questions