Notes on call/cc. A break debugging facility is the simplest use of first-class continuations. > (define top-k 'ignored) > (call/cc (lambda (k) (set! top-k k))) > (define continue (lambda () "no break to continue")) > (define break (lambda (v) (call/cc (lambda (k) (set! continue k) (top-k v))))) > (+ (break 'break-one) (break 'break-two)) break-two > (continue 3) break-one > (continue 2) 5 Other uses of first-class continuations: - breadth-first search - coroutines (EOPL section 9.4, not responsible for) - multi-tasking EXCEPTIONS Java exception syntax: throw new-exception try { /* try block */ } catch (ExceptionType e1) { /* catch statement 1 */ } catch (ExceptionType e2) { /* cath statement 2 */ ... } finally { /* finalization code */ } To see how this may be implemented in Scheme, we first need DYNAMIC-WIND to implement FLUID-LET properly. (DYNAMIC-WIND prelude-thunk body-thunk postlude-thunk) usage examples: robots, files implementation in section 9.5: not responsible for, can be simpler (fluid-let ((var exp)) body) ==> (let ((var^ exp)) (let ((swap (lambda () (let ((temp var)) (set! var var^) (set! var^ temp))))) (dynamic-wind swap (lambda () body) swap))) Usage examples: binding I/O parameters (actually, Chez Scheme uses parameters instead), Java-style FINALLY clause. (define make-parameter ; doesn't have Chez Scheme's guards (lambda (v) (lambda args (if (null? args) v (set! v (car args)))))) Exercise: define (PARAMIZE param value thunk) (define-record bad-input-exn (input)) (try (lambda () (raise (make-bad-input-exn "junk"))) bad-input-exn? (lambda (input) (printf "Bad input: ~s~n" input))) (define raise (lambda (v) (error "Unhandled exception:" v))) (define try (lambda (body-thunk guard-proc handler-proc) (call/cc (lambda (k) (fluid-let ((raise (let ((outer-raise raise)) (lambda (v) (if (guard-proc v) (k (handler-proc v)) (outer-raise v)))))) (body-thunk))))))