clojure.core.memoize
core.memoize is a memoization library offering functionality above Clojure's core `memoize`
function in the following ways:
**Pluggable memoization**
core.memoize allows for different back-end cache implmentations to be used as appropriate without
changing the memoization modus operandi.
**Manipulable memoization**
Because core.memoize allows you to access a function's memoization store, you do interesting things like
clear it, modify it, and save it for later.
(build-memoizer cache-factory f & args)
Builds a function that given a function, returns a pluggable memoized
version of it. `build-memoizer` Takes a cache factory function, a function
to memoize, and the arguments to the factory. At least one of those
functions should be the function to be memoized.
(fifo f)
(fifo f base)
(fifo f tkey threshold)
(fifo f base key threshold)
Works the same as the basic memoization function (i.e. `memo`
and `core.memoize` except when a given threshold is breached.
Observe the following:
(require '[clojure.core.memoize :as memo])
(def id (memo/fifo identity :fifo/threshold 2))
(id 42)
(id 43)
(snapshot id)
;=> {[42] 42, [43] 43}
As you see, the limit of `2` has not been breached yet, but
if you call again with another value, then it is:
(id 44)
(snapshot id)
;=> {[44] 44, [43] 43}
That is, the oldest entry `42` is pushed out of the
memoization cache. This is the standard **F**irst **I**n
**F**irst **O**ut behavior.
(lru f)
(lru f base)
(lru f tkey threshold)
(lru f base key threshold)
Works the same as the basic memoization function (i.e. `memo`
and `core.memoize` except when a given threshold is breached.
Observe the following:
(require '[clojure.core.memoize :as memo])
(def id (memo/lru identity :lru/threshold 2))
(id 42)
(id 43)
(snapshot id)
;=> {[42] 42, [43] 43}
At this point the cache has not yet crossed the set threshold
of `2`, but if you execute yet another call the story will
change:
(id 44)
(snapshot id)
;=> {[44] 44, [43] 43}
At this point the operation of the LRU cache looks exactly
the same at the FIFO cache. However, the difference becomes
apparent on further use:
(id 43)
(id 0)
(snapshot id)
;=> {[0] 0, [43] 43}
As you see, once again calling `id` with the argument `43`
will expose the LRU nature of the underlying cache. That is,
when the threshold is passed, the cache will expel the
**L**east **R**ecently **U**sed element in favor of the new.
(lu f)
(lu f base)
(lu f tkey threshold)
(lu f base key threshold)
Similar to the implementation of memo-lru, except that this
function removes all cache values whose usage value is
smallest:
(require '[clojure.core.memoize :as memo])
(def id (memo/lu identity :lu/threshold 3))
(id 42)
(id 42)
(id 43)
(id 44)
(snapshot id)
;=> {[44] 44, [42] 42}
The **L**east **U**sed values are cleared on cache misses.
(memo f)
(memo f seed)
Used as a more flexible alternative to Clojure's core `memoization`
function. Memoized functions built using `memo` will respond to
the core.memo manipulable memoization utilities. As a nice bonus,
you can use `memo` in place of `memoize` without any additional
changes.
The default way to use this function is to simply apply a function
that will be memoized. Additionally, you may also supply a map
of the form `'{[42] 42, [108] 108}` where keys are a vector
mapping expected argument values to arity positions. The map values
are the return values of the memoized function.
You can access the memoization cache directly via the `:clojure.core.memoize/cache` key
on the memoized function's metadata. However, it is advised to
use the core.memo primitives instead as implementation details may
change over time.
(memo-clear! f)
(memo-clear! f args)
Reaches into an core.memo-memoized function and clears the cache. This is a
destructive operation and should be used with care.
When the second argument is a vector of input arguments, clears cache only
for argument vector.
Keep in mind that depending on what other threads or doing, an
immediate call to `snapshot` may not yield an empty cache. That's
cool though, we've learned to deal with that stuff in Clojure by
now.
(memo-swap! f base)
Takes a core.memo-populated function and a map and replaces the memoization cache
with the supplied map. This is potentially some serious voodoo,
since you can effectively change the semantics of a function on the fly.
(def id (memo identity))
(memo-swap! id '{[13] :omg})
(id 13)
;=> :omg
With great power comes ... yadda yadda yadda.
(memoized? f)
Returns true if a function has an core.memo-placed cache, false otherwise.
(snapshot memoized-fn)
Returns a snapshot of a core.memo-placed memoization cache. By snapshot
you can infer that what you get is only the cache contents at a
moment in time.
(ttl f)
(ttl f base)
(ttl f tkey threshold)
(ttl f base key threshold)
Unlike many of the other core.memo memoization functions,
`memo-ttl`'s cache policy is time-based rather than algortihmic
or explicit. When memoizing a function using `memo-ttl` you
should provide a **T**ime **T**o **L**ive parameter in
milliseconds.
(require '[clojure.core.memoize :as memo])
(def id (memo/ttl identity :ttl/threshold 5000))
(id 42)
(snapshot id)
;=> {[42] 42}
... wait 5 seconds ...
(id 43)
(snapshot id)
;=> {[43] 43}
The expired cache entries will be removed on each cache **miss**.