( Редактировать : я ошибся из-за того, что смог сделать более компактную реализацию, используя специальные операторы управления. Можно заставить обработчик работать в хвостовом положении относительно формы handle
, но я не знаю ни одного способа оценить тело в положении хвоста.)
Прежде всего, вы специально пытаетесь реализовать обработку исключений, когда тело формы handle
находится в хвостовой позиции относительно самой формы handle
?Если нет, то есть гораздо более простые способы реализации обработки исключений в терминах простых продолжений экранирования.
Если вы действительно хотите реализовать исключение "безопасный для пространства" или "правильно заданный рекурсивный"Обращаясь, однако, к прочтению.
Сложность реализации handle
безопасным для пространства способом состоит в том, чтобы избежать вставки дополнительного кадра стека в «исключение не возбуждено»путь, вам нужна возможность размотать стек и возобновить оценку с выражением в этом контексте.Или, эквивалентно, возобновите оценку, вызвав процедуру в этом контексте.Это отличается от того, что обеспечивает call/cc
;он позволяет только разматывать стек и затем сразу возвращать значение в этот контекст.
Вы можете смоделировать дополнительную мощность с помощью call/cc
за счет вставки дополнительного кадра стека (таким образом, телоне находится в хвостовой позиции):
;; call/cc : ((Any -> None) -> Any) -> Any
;; call/cc/apply : (((-> Any) -> None) -> Any) -> Any
(define (call/cc/apply proc)
((call/cc (lambda (k) (let ([v (proc k)]) (lambda () v))))))
Дополнительный кадр стека получается в результате применения выражения call/cc
.
Можете ли вы устранить необходимость в этомдополнительный кадр стека?Да!Но не с shift
и reset
.
Проблема, с которой вы столкнулись, заключается в том, что (abort e)
(где abort
соответствует оператору Фелляйзена и A Хиба) не совпадает с (shift _ e)
.Если вы посмотрите на документы для сдвига и сброса , вы увидите следующие правила сокращения:
(reset val) => val
(reset E[(shift k expr)]) => (reset ((lambda (k) expr)
(lambda (v) (reset E[v]))))
; where E has no reset
То есть shift
не удалить его разграничение reset
, и этот упрямый reset
- это то, что мешает вам выпрыгнуть из вашего обработчика уровня 2 прямо в ваш обработчик уровня 1 без запуска (print "level-2 close")
.Вам нужно выбрать разделитель и управляющий оператор, который позволит вам удалить разделитель.
Вы не можете сделать это с reset
и shift
.
Вы не можете сделать это с prompt
и control
.
Вы можете сделать это с prompt0
и control0
.
Вы можете сделать это с %
и fcontrol
(и правым обработчиком).
И, конечно, вы можете сделатьэто с call-with-continuation-prompt
и abort-current-continuation
(и правым обработчиком).