Here is an improved memoize function that also takes a time-to-live
argument. Useful when you want to expire results from the cache.
I'm using it to cache query results from a database. This probably
breaks some rules about functional programming though :-)
(defn expire-cached-results [cached-results time-to-live]
"Expire items from the cached function results."
(into {} (filter (fn [[k v]] (> time-to-live (- (System/
currentTimeMillis) (:time v)))) cached-results)))
(defn my-memoize
"Returns a memoized version of a referentially transparent
function. The
memoized version of the function keeps a cache of the mapping from
arguments
to results and, when calls with the same arguments are repeated
often, has
higher performance at the expense of higher memory use. Cached
results are
removed from the cache when their time to live value expires."
[function time-to-live]
(let [cached-results (atom {})]
(fn [& arguments]
(swap! cached-results expire-cached-results time-to-live)
(println cached-results)
(if-let [entry (find @cached-results arguments)]
(:result (val entry))
(let [result (apply function arguments)]
(swap! cached-results assoc arguments { :result
result :time (System/currentTimeMillis)})
result)))))
Sample usage:
(defn calculation [n]
(println "Doing some bistromath")
(* n 42))
(def foo (my-memoize calculation 5000))
;; First execution
user> (foo 10)
Doing some bistromath
420
;; Executed immediately after first time - cached result
user> (foo 10)
420
;; Executed after 5 seconds - not cached anymore
user> (foo 10)
Doing some bistromath
420
This is some of my first Clojure code so it might not be the
greatest ... yet!
(defn my-memoize
"Returns a memoized version of a referentially transparent
function. The
memoized version of the function keeps a cache of the mapping from
arguments
to results and, when calls with the same arguments are repeated
often, has
higher performance at the expense of higher memory use. Cached
results are
removed from the cache when their time to live value expires."
[function time-to-live]
(let [cached-results (atom {})]
(fn [& arguments]
(swap! cached-results expire-cached-results time-to-live)
(println cached-results)
(if-let [entry (find @cached-results arguments)]
(:result (val entry))
(let [result (apply function arguments)]
(swap! cached-results assoc arguments { :result
result :time (System/currentTimeMillis)})
result)))))