A procedure can remember what happened.
A local binding becomes state when later calls can observe the value left by earlier calls.
What changes when an answer depends on the calls that came before it?
- Distinguish a returned value from stored state
- Follow assignment across successive calls
- Recognize when call order becomes observable
withdraw closes over the balance binding. Each successful call changes that binding before returning its new value, so the next call begins from a different balance.
Three nested single-binding let expressions make the sequence explicit. Each result therefore reflects the state left by the preceding call instead of starting again from 100.
(let ((balance 100))
(let ((withdraw
(lambda (amount)
(if (>= balance amount)
(begin
(set! balance (- balance amount))
balance)
'insufficient-funds))))
(let ((first (withdraw 25)))
(let ((second (withdraw 25)))
(let ((third (withdraw 60)))
(list first second third))))))- Output
- —
- Value
- —
- Diagnostic
- —
The first program returns (75 50 insufficient-funds). The failed withdrawal leaves the balance at 50.
Find each application of withdraw and the set! expression inside the two successful calls. The final call reaches the other branch and performs no assignment.
Change the program before you read the hint.
Insert a withdrawal of 10 between the two withdrawals of 25. Predict every returned value before running the changed sequence.
Show one hint
Write down the balance after each successful call. A failed call does not change it.