182CS 538 Spring 2008©ContinuationsIn our Scheme implementation of*list, we’d like a way to delaydoing any multiplies until weknow no zeros appear in the list.One approach is to build acontinuation—a function thatrepresents the context in which afunction’s return value will beused:(define (*listC L con) (cond ((null? L) (con 1)) ((= 0 (car L)) 0) (else (*listC (cdr L) (lambda (n) (* n (con (car L))))) ) ))183CS 538 Spring 2008©The top-level call is(*listC L (lambda (x) x))For ordinary lists *listC expandsto a series of multiplies, just like*list did.(define (id x) x)(*listC '(1 2 3) id) ⇒(*listC '(2 3) (lambda (n) (* n (id 1))))≡(*listC '(2 3) (lambda (n) (* n 1)))⇒(*listC '(3) (lambda (n) (* n (* 2 1))))≡(*listC '(3) (lambda (n) (* n 2)))⇒(*listC () (lambda (n) (* n (* 3 2))))≡(*listC () (lambda (n) (* n 6)))⇒ (* 1 6) ⇒ 6184CS 538 Spring 2008©But for a list with a zero in it, weget a different execution path:(*listC '(1 0 3) id) ⇒(*listC '(0 3)(lambda (n) (* n (id 1))))⇒ 0No multiplies are done!185CS 538 Spring 2008©Another Example ofContinuationsLet’s redo our list multiplyexample so that if a zero is seenin the list we return a functionthat computes the product of allthe non-zero values and aparameter that is the“replacement value” for theunwanted zero value. Thefunction gives the caller a chanceto correct a probable error in theinput data.We create(*list2 L) ≡Product of all integers in L ifno zero appearselse(lambda (n) (* n product-of-all-nonzeros-in-L)186CS 538 Spring 2008©(define (*list2 L) (*listE L id))(define (*listE L con) (cond ((null? L) (con 1)) ((= 0 (car L)) (lambda(n) (* (con n) (*listE (cdr L) id)))) (else (*listE (cdr L) (lambda(m) (* m (con (car L)))))) ))187CS 538 Spring 2008©In the following, we check to seeif *list2 returns a number or afunction. If a function is returned,we call it with 1, effectivelyremoving 0 from the list(let ( (V (*list2 L)) ) (if (number? V) V (V 1) ))188CS 538 Spring 2008©For ordinary lists *list2 expandsto a series of multiplies, just like*list did.(*listE '(1 2 3) id) ⇒(*listE '(2 3) (lambda (m) (* m (id 1))))≡(*listE '(2 3) (lambda (m) (* m 1)))⇒(*listE '(3) (lambda (m) (* m (* 2 1))))≡(*listE '(3) (lambda (m) (* m 2)))⇒(*listE () (lambda (m) (* m (* 3 2))))≡(*listE () (lambda (n) (* n 6)))⇒ (* 1 6) ⇒ 6189CS 538 Spring 2008©But for a list with a zero in it, weget a different execution path:(*listE '(1 0 3) id) ⇒(*listE '(0 3) (lambda (m) (* m (id 1))))⇒(lambda (n) (* (con n) (* listE '(3) id)))≡(lambda (n) (* (* n 1)(* listE '(3) id)))≡(lambda (n) (* (* n 1) 3))This function multiplies n, thereplacement value for 0, by 1 and3, the non-zero values in the inputlist.190CS 538 Spring 2008©But note that only one zero valuein the list is handled correctly!Why?(define (*listE L con) (cond ((null? L) (con 1)) ((= 0 (car L)) (lambda(n) (* (con n)(*listE (cdr L) id)))) (else (*listE (cdr L) (lambda(m) (* m (con (car L)))))) ))191CS 538 Spring 2008©Continuations in SchemeScheme provides a built-inmechanism for creatingcontinuations. It has a long name:call-with-current-continuationThis name is often abbreviated ascall/cc(perhaps using define).call/cc takes a single function asits argument. That function alsotakes a single argument. That is,we usecall/cc as(call/cc funct) wherefunct ≡ (lambda (con) (body))call/cccalls the function that itis given with the “currentcontinuation” as the function’sargument.192CS 538 Spring 2008©Current ContinuationsWhat is the current continuation?It is itself a function of oneargument. The currentcontinuation function representsthe execution context withinwhich the call/cc appears. Theargument to the continuation is avalue to be substituted as thereturn value of call/cc in thatexecution context.For example, given(+ (fct n) 3)the current continuation for(fct n) is (lambda (x) (+ x 3)Given (* 2 (+ (fct z) 10))the current continuation for (fct z) is(lambda (m) (* 2 (+ m 10))193CS 538 Spring 2008©To use call/cc to grab acontinuation in (say) (+ (fct n) 3)we make (fct n) the body of afunction of one argument. Call thatargument return. We therefore build(lambda (return) (fct n))Then(call/cc (lambda (return) (fct n)))binds the current continuation toreturn and executes (fct n).We can ignore the currentcontinuation bound to returnand do a normal returnorwe can use return to force areturn to the calling context of thecall/cc.The call (return value) forcesvalue to be returned as the valueof call/cc in its context of call.194CS 538 Spring 2008©Example:(define (g con) (con 5))Now during evaluation no divideby zero error occurs. Rather, when(g return) is called, 5 is passedto con, which is bound to return.Therefore 5 is used as the value ofthe call to call/cc, and 50 iscomputed.(* (call/cc (lambda(return) (/ (g return) 0))) 10)return195CS 538 Spring 2008©Continuations are JustFunctionsContinuations may be saved invariables or data structures andcalled in the future to “reactive” acompleted or suspendedcomputation.(define CC ())(define (F) (let ( (v (call/cc (lambda(here) (set! CC here) 1))))(display "The ans is: ") (display v)(newline)) )This displays The ans is: 1At any time in the future, (CC 10)will display The ans is: 10196CS 538 Spring 2008©List Multiplication RevisitedWe can use call/cc toreimplement the original *list toforce an immediate return of 0(much like a throw in Java):(define (*listc L return) (cond ((null? L) 1) ((= 0 (car L)) (return 0)) (else (* (car L)(*listc (cdr L) return)))) )(define (*list L) (call/cc (lambda (return) (*listc L return)) ))A 0 in L forces a call of (return0) which makes 0 the value ofcall/cc.197CS 538 Spring 2008©Interactive Replacement ofError ValuesUsing continuations, we can alsoredo *listE so that zeroes canbe replaced interactively! Multiplezeroes (in both original andreplacement values) are correctlyhandled.(define (*list L) (let ( (V (call/cc (lambda (here) (*liste L here)))) ) (if (number? V) V (begin (display "Enter new value for 0") (newline) (newline) (V (read)) ) ) ))198CS 538 Spring 2008©(define (*liste L return) (if (null? L) 1 (let loop ((value (car L))) (if (= 0 value) (loop
View Full Document