In Clojure if I memoize a function, name it f and call it on an argument a.
If a is a large lazy value, does memoize return a value based on matching the thunk as opposed to forcing the evaluation of a and matching on the result?
Where a thunk is the unevaluated part of the lazy sequence.
If this isn’t the case is there a built-in way to get this behaviour?
Thanks!
As stated by mikera,
memoizedoesn’t handle infinite lazy seqs. I’m adding this answer to provide a short description of the implementation reasons for this (plus two ideas for identity-based memoization schemes, one simple, one more complex). (Edit: actually there is a simple general identity-based solution, see below.)Why it doesn’t work
memoizeuses a hash map to store the mapping from arguments to values and hash maps useclojure.lang.Util/hasheqwhen determining if an object is one of their keys (except empty maps which just returnfalse). Sincehasheq‘s implementation for lazy seqs forces the entirety of the seq, asking any map if an infinite lazy seq is one of its keys will cause it to go into an infinite, memory-exhausting loop. Thus the same goes formemoize.Strictly speaking, initially the map is an array map. (In Clojure, for reasons of efficiency, small maps are usually array maps; if enough items are
assoc‘d onto an array map, the return value becomes a hash map.) However non-empty array maps also fail to handle infinite lazy seqs due to a similar reason involving an equivalence-checking method.A solution
System/identityHashCodereturns whateverhashCodewould return for a given objects if it used the default implementation (whether or not itshashCodeis overridden).Now you can do this (which wouldn’t work with the regular
memoize):Original discussion of alternative implementations follows.
I don’t think there is a built-in solution using pointer equality. To implement one as general as
memoize, you’d have to implement a map structure using pointer-equality-based hashing (viz.System/identityHashCode). Or you could build a simple “most recently used” cache withclojure.lang.PersistentQueue.