Because reset-procedure and value-procedure are not within the scope of
previous-power-of-two ; or , to use the terminology of the book , within the
"gatekeeper's list" created for previous-power-of-two .Compare with an
earlier example :
(setf g1
(let ((previous-power-of-two 1))
#'(lambda () ..... )))
This works because the lambda is within the scope for previous-power-of-two
created by LET .I suspect that the authors made a mistake : they intended to
use LET* for the generator-with-dispatch-procedure example but they forgot
and in their testing they always happened to do first
(funcall (funcall generator-with-dispatch-procedure 'reset))
hence they never noticed the mistake. The way they have written the code ,
the first time you do
(funcall (funcall generator-with-dispatch-procedure 'reset))
a special variable previous-power-of-two gets created. Note that then
you can just type on the REPL
previous-power-of-two
and it shows you its current value which violates what the book says on page
217 : "However some programmers dislike having the state variable exposed. In
principle other procedures could alter it inadvertently." and the examples
which follow {including the one your question is about} are meant to show you
how you can avoid this.
With the definition in the book , I have the following interaction with SBCL
{omitting warnings}
* (funcall (funcall generator-with-dispatch-procedure 'reset))
1
* previous-power-of-two
1
* (funcall (funcall generator-with-dispatch-procedure 'value))
2
* (setf previous-power-of-two 7)
7
* (funcall (funcall generator-with-dispatch-procedure 'value))
14
Now if I terminate and restart SBCL and replace the let in the code of
the book by let* , I get the following :
* (funcall (funcall generator-with-dispatch-procedure 'value))
2
{ Note that there is no error now. }
* previous-power-of-two
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING {A8346F9}>:
The variable PREVIOUS-POWER-OF-TWO is unbound.
* (setf previous-power-of-two 7)
7
* (funcall (funcall generator-with-dispatch-procedure 'value))
4
* (funcall (funcall generator-with-dispatch-procedure 'reset))
1
* (funcall (funcall generator-with-dispatch-procedure 'value))
2
* previous-power-of-two
7
When you do (funcall generator-with-dispatch-procedure ...) , the 2
functions access the lexical previous-power-of-two which is private to
the 2 functions and has a separate value from the special
previous-power-of-two which was created when I did
(setf previous-power-of-two 7)
.I believe this is what the book was aiming to exhibit.
--
vlaho.ninja/prog