; The implementation of shift/reset in terms of call/cc is justified
; only in very restricted circumstances, where shift/reset is the only
; effect.
; In full Scheme, the implementation becomes inconsistent with the small-step
; semantics of shift/reset.
;
; We observe the inconsistency using fluid variables of Scheme48
; and its implementation of shift/reset (which removes the memory
; leak problem of the original implementation).
;
; To run the example, start scheme48 and do the following:
;
; ,open fluids
; ,open signals escapes
; ,load =scheme48/misc/shift-reset.scm
; ,load traps-s48.scm
;
; The first line loads the structure `fluids'. The next two lines
; make available the control operators shift and reset.
; The last line loads the present code.
;
; This code is based on the one accompanying the paper Delimited
; Dynamic Binding (ICFP 2006).
(define my-fluid (make-fluid #f))
; de-referencing of my-fluid
(define (dref) (fluid my-fluid))
; dynamic binding: execute thunk in the dynamic env obtained by binding
; my-fluid to new-val
(define (dlet new-val thunk) (let-fluid my-fluid new-val thunk))
; The first test
(define (test1)
(dlet 1
(lambda ()
(list (dref) (dref)
(dlet 2
(lambda ()
(list (dref) (dref))))))))
(display (test1)) (newline)
; (1 1 (2 2))
;------------------------------------------------------------------------
; Counter-example 1: shift evaluates its body without removing
; the captured continuation, contrary to its small-step semantics.
(dlet 1
(lambda ()
(reset
(dlet 2
(lambda ()
(shift k (begin (display (dref)) (newline))))))))
; ==> 2
; The observed result 2 differs from the one predicted by the
; small-step semantics of shift:
; According to the small-step semantics of shift, the body of shift
; is to be evaluated after the captured delimited context is removed.
; That is, the one-step reduction of the above expression should be
(dlet 1
(lambda ()
(reset
(begin (display (dref)) (newline)))))
; whose result is 1.
;------------------------------------------------------------------------
; Counter-example 2: Invoking the shift-captured continuation removes
; the context of the caller. The captured continuation therefore does
; not at all behave like a function -- contrary to the semantics of shift.
; According to the semantics of shift, captured-k should be
; (lambda (x) (reset x (display (dref) (newline)))), which is
; equivalent to (lambda (x) (display (dref) (newline)))
(let ((expected-captured-k
(lambda (x) (reset (begin x (display (dref)) (newline)))))
(captured-k
(dlet 9
(lambda ()
(reset
(begin
(shift k k)
(display (dref)) (newline)))))))
(dlet 3
(lambda ()
(display "Expected: ") (expected-captured-k #f)
(display "Found: ") (captured-k #f)
)))
; Expected: 3
; Found: 9