The book Structure and Interpretation of Computer Programs introduces a memoizing procedure as follows:
(define (memo-proc proc)
(let ((already-run? false) (result false))
(lambda ()
(if (not already-run?)
(begin (set! result (proc))
(set! already-run? true)
result)
result))))
while suggesting the definition of delayed execution, (delay <exp>)
be (memo-proc (lambda () <exp>))
. A delayed object can be forced using the following procedure:
(define (force delayed-object)
(delayed-object))
In the chapter which gives these definitions, computations are done using streams. Each stream is a pair with a head, and a delayed tail.
However, I don't see how memoization is achieved without using a lookup table, or some other kind of data structure which accumulates the previous calls.
The chapter which includes these definitions are here.
A lookup table would be useful when we are memoizing a single procedure with various arguments. Then, we would put arguments as keys and the result of the procedure as values. In this case, we have nullary procedures hence we don't need a lookup table. All we need would be a set of delayed objects we have created so far. However, closures are used here.
According to the definition of memo-proc
above, each delayed object actually is a closure with values already-run?
and result
, which are both initialised to false
. However, since each delayed object inside the call proc
would have their own closures with their own local already-run?
and result
, modifying them wouldn't change the other ones in the call tree. Hence, I'm feeling like a memoized value won't ever be read by any other procedures again.
So my question is, what am I thinking wrong or what is the correct explanation of how everything works?
(memoize proc)
is invoked, doesn't it create a new lambda from scratch, whereresult
is nil? So, what is stopping the value ofresult
being nil in an inner call to the same memoized procedure? – Handyman