Моя мутная ментальная модель вызова / cc схемы:
1) установить новую область видимости (назовем это current-scope)
2) вызвать функцию аргумента с текущим продолжением.
Текущее продолжение по сути является переходом к концу current-scope. IE, вызывающий current-продолжение, переходит в конец текущей области (и возвращает те аргументы, с которыми было вызвано current-продолжение).
Поэтому, когда установлено продолжение call / cc! к некоторой переменной (кешируем ее на потом) внутри другого вызова / cc и вызывается продолжение внешнего вызова / cc, мы переходим к концу внешнего продолжения.
Теперь весь оставленный код свободно плавает в памятипотому что сборщик мусора не дошел до него. Если мы все еще можем получить доступ к сохраненному в кэше продолжению для внутреннего вызова / cc-продолжения, тогда схема определяет, что код достижим, и не удаляет область, которую мы оставили. Таким образом, если мы вызываем кэшированное продолжение, мы можем безопасно перейти «назад во времени» к концу области, которую мы оставили.
На основании вышеизложенного этот код работает в моей схеме REPL:
> (define time-machine 'delorean)
> (define (hit-88-miles-per-hour)
(call/cc (lambda (cc)
(let ([shenanigans "Do things with doc"])
(call/cc (lambda (innercc)
(set! time-machine innercc)
(cc "Back to the future!")))
shenanigans))))
> (hit-88-miles-per-hour)
"Back to the future!"
> (time-machine)
"Do things with doc"
Мое понимание более или менее верно? Если нет, пожалуйста, исправьте, потому что продолжение было серьезным умственным упражнением, чтобы понять.