CS 541 Lecture -*- Outline -*- ** Continuations (idea due to Strachey, Wadsworth, Morris) Notes in part based on Scheme and Art of Programming, chapter 16. idea: go left two blocks then "ask someone else"... procedure that represents the "rest" of the program configuration of the run-time stack, return address *** flavors of continuations available in semantics **** normal: continuation for code following a statement (etc.) **** exceptional: any other continuation (e.g., abort). e.g., error in Scheme uses an exceptional continuation *** uses in programming **** return multiple values --------------- (define (qr n d cont err) ; if d = 0, then call err with d as an argument, ; otherwise call cont with the quotient of n by d and the remainder (if (zero? d) (err d) (cont (quotient n d) (remainder n d)))) (qr 16 3 (lambda (q r) (+ q r)) (lambda (d) (write "oops"))) ;Value: 6 --------------- **** exception handling --------------- (define (first-negative lst do-if-none) ; effect: if there are no negative numbers in lst, call do-if-none, ; otherwise return the first negative number in lst (cond ((null? lst) (do-if-none)) ((negative? (car lst)) (car lst)) (else (first-negative (cdr lst) do-if-none)))) -------------- *** Contexts: formalizing "the rest of the program" (S&F, section 16.1) (+ 3 ( * 4 (+ 5 6))) ==> 47 what's the context (rest of the expression) for (+ 5 6)? (lambda ( _ ) (+ 3 (* 4 _))) what does applying this context to 11 yield? context of (* 3 4) in (* (+ (* 3 4) 5) 2) is (lambda (_) (* (+ _ 5) 2)) steps: 1. replace expression by _, 2. wrap in lambda (abstract it out). **** a "reduced form" for contexts extend step 1 by evaluating as far as possible. --------------- (let ((n 1)) (begin (if (zero? n) (writeln (+ 3 (* 4 (+ 5 6)))) (writeln (* (+ (* 3 4) 5) 2))) n)) ; context of (* 3 4) is (lambda ( _ ) (begin (writeln (* (+ _ 5) 2)) n)) --------------- this closure is considered to be taken within the scope of the above, so n will be remembered to be 1 **** contexts of hidden expressions --------------- (define tester (lambda (n) (begin (if (zero? n) (writeln (+ 3 (* 4 (+ 5 6)))) (writeln (* (+ (* 3 4) 5) 2))) n))) ; context of (* 3 4) in (* 10 (tester 1)) is (lambda ( _ ) (* 10 (begin (writeln (* (+ _ 5) 2)) n))) ---------------- **** contexts in recursive procedures --------------- (define map-add1 (lambda (ls) (if (null? ls) (cons (+ 3 (* 4 5)) '()) (cons (add1 (car ls)) (map-add1 (cdr ls)))))) ; context of (* 4 5) in (cons 0 (map-add1 '(1 3 5))) (lambda ( _ ) (cons 0 (cons 2 (cons 4 (cons 6 (cons (+ 3 _) '())))))) --------------- run it until _ stops it. *** escape procedures abandon their context! return value without passing it along (bandits) ------------- (define escape-* (escaper *)) (+ (escape-* 5 2) 3) ;Value: 10 (+ ((escaper (lambda (x) (- (* x 3) 7))) 5) 4) ;Value: 8 (/ (+ ((escaper (lambda (x) (- (* x 3) 7))) 5) 4) 2) ;Value: 8 ------------- rule is if e is an escape procedure, then (compose f e) = e (f (e expr)) = (e expr) for all expr what is context of (e expr) in (f (e expr))? (lambda ( _ ) (f _)) the context is abandoned *** in Scheme: call-with-current-continuation, call/cc (some shorten this to call/cc) gives access to current continuation (call-with-current-continuation p), where p is a procedure of one argument ---------------- (define call/cc call-with-current-continuation) (call/cc receiver) = (receiver continuation) where continuation = (escaper c) and c = context of (call/cc receiver) in some expr E ---------------- connection with terminal transition systems... --------------- (define r (lambda (cont) 6)) (+ 3 (* 4 (call/cc r))) ; = (+ 3 (* 4 (r (escaper (lambda (_) (+ 3 (* 4 _))))))) ;Value: 27 (call/cc (lambda (err-value) (qr 16 3 (lambda (q r) (+ q r)) err-value))) ;Value: 6 (call/cc (lambda (err-value) (qr 16 0 (lambda (q r) (+ q r)) err-value))) ;Value: 0 (define (first-negative lst do-if-none) (call/cc (lambda (exit) (for-each (lambda (x) (if (negative? x) (exit x))) lst) (do-if-none lst)))) (first-negative '(1 2 -3 4 5) (lambda (x) (write "oops"))) ;Value: -3 (first-negative '(1 2 3) (lambda (x) (write "oops"))) ; writes "oops" ;No value ---------------