Title: Advanced Scheme
1Advanced Scheme
2Continuations
- continuations allow you to save a computation at
any place in its execution. - In scheme, use the built-in function
call-with-current-continuation - Can abbreviate as call/cc in most versions of
scheme (including Dr Scheme) - Can think of a continuation as a bookmark into a
computation
3call/cc
- Call/cc is a built-in function
- Takes as an argument a procedure of one parameter
- Call/cc calls the passed function and binds the
continuation to the parameter of the function. - When the parameter of the procedure is used in
its body, computation jumps to the continuation
and passes the argument to that point of the
continuation
4example
- In this example, call/cc is called after the 1
computation is done - The continuation at this point is bound to k and
passed to the lambda - k is used in the call (k 3)
- At this point the continuation is executed, ie
execution is restarted right after the ( 1 and
the argument of k (ie 3) is passed as the result
of the continuation. - In other words it ignores any computation that
occurred after the continuation started, but
before the continuation was applied. - ( 1 (call/cc
- (lambda (k)
- ( 2 (k 3)))))
- 4
- gt
5example
The continuation captures the computation. In
this case it occurs right after the 1, so when
the continuation is used it will return its value
to the 1 computation.
- ( 1 (call/cc
- (lambda (k)
- ( 2 (k 3)))))
- 4
- gt
6example
- ( 1 (call/cc
- (lambda (k)
- ( 2 (k 3)))))
- 4
- gt
7Example 2
- In this example, call/cc is called after the 1
computation is done, but there is more
computation (ie values) after the call/cc
function - The continuation at the call/cc is bound to k and
passed to the lambda - k is used in the call (k 3)
- At this point the continuation is executed, ie
execution is restarted right after the ( 1 and
the argument of k (ie 3) is passed as the result
of the continuation. - But there is more computation to be done after
the call/cc, so the 4 and 10 are added to the
result also! - ( 1 (call/cc
- (lambda (k)
- ( 2 (k 3)))) 4 10)
- 18
- gt
8Example 2
The continuation captures the computation in the
middle. In this case it occurs right after the
1, but before the adding of 4 and 10.
- ( 1 (call/cc
- (lambda (k)
- ( 2 (k 3)))) 4 10)
- 18
- gt
When k (the continuation) is called, we pick up
at the 1, pass in the argument of k (I.e., 3)
and then finish the computation (add 4 and 10)
9Escaping Continuations
- Continuations can be used to escape from
computations - Can conceptualize as jumping out of a procedure
10Escaping Continuations example
- (define list-product
- (lambda (s)
- (letrec
- ((multList
- (lambda (s)
- (if (null? s)
- 1
- ( (car s) (multList(cdr s)))
- ))))
- (multList s))
- )
- )
- Works, but inefficient
- What if have a long list and end item is 0?
- Will return through the entire list and multiply
each item by 0!
11Escaping Continuations example
- One solution tail recursion
- Another solution continuation
- (define list-product
- (lambda (s)
- (call/cc
- (lambda (exit)
- (letrec
- ((multList
- (lambda (s)
- (if (null? s)
- 1
- (if ( (car s) 0) (exit 0)
- ( (car s) (multList(cdr s)))
- )))))
- (multList s))
- ))
- ))
12Escaping Continuations example 2
- Find an element in a list
- Use a built-in function for-each
- return does not exist in scheme
- (and yes, I know that we could use a recursive
function instead) - (define find-item
- (lambda (wanted? theList)
- (for-each
- (lambda (element)
- (if (wanted? element)
- (return element)))
- theList)
- f))
- To call
- (find-item (lambda (x) (equal? x 'a)) '(b c d a e
f g))
This code wont run! The function return doesnt
exist!
How can we return?
13Escaping Continuations example 2
- Instead of return use a continuation
- (define find-item
- (lambda (wanted? theList)
- (call/cc
- (lambda (return)
- (for-each
- (lambda (element)
- (if (wanted? element)
- (return t)))
- theList)
- f))))
The return becomes a continuation
14Escaping Continuations example 3deep recursion
- adds a number to the product of a list of
numbers - (define product
- (lambda (n nums)
- (let ((receiver
- (lambda (exit-on-zero)
- (letrec
- ((product
- (lambda (nums)
- (cond
- ((null? nums) 1)
- ((number? (car nums))
- (cond
- ((zero? (car
nums))(exit-on-zero 0)) - (else ( (car nums)
- (product (cdr
nums)))))) - (else ( (product (car
nums)) - (product (cdr
nums)))))))) - ( n (product nums))))))
- (call/cc receiver))))
The exit-on-zero becomes a continuation
15Saving Continuations
- Can save a continuation and use it later
- (define r f)
- ( 1 (call/cc
- (lambda (k)
- (set! r k)
- (k 3))))
4 gt (r 1) 2 gt (r 10) 11 gt (r 32) 33 gt ( 3 4 (r
20)) 21 gt
16Background writeln
- first must define writeln
- (define writeln
- (lambda lst
- need a helper function to deal with the lst
a recursive call to writeln - will place lst into another list
- (letrec ((helper
- (lambda (newlst)
- (if (not (null? newlst))
- (begin
- (display (car newlst))
- (display \space)
- (helper (cdr newlst)))
- (newline)))))
- (helper lst))))
17Looping with Continuations
- loops with continuations
- (define countdown
- (lambda (n)
- (writeln "This only appears once")
- (let ((pair (message "Exit" (attempt (message
"Enter" n))))) - (let ((v (car pair))
- (returner (cadr pair)))
- (writeln " The non-negative-number "
v) - (if (positive? v)
- (returner (list (sub1 v) returner))
- (writeln "Blastoff!"))))))
- (define message
- (lambda (direction value)
- (writeln " " direction "ing attempt with
value " value) - value))
- (define attempt
- (lambda (n)
- Welcome to DrScheme, version 209.
- Language Graphical (MrEd, includes MzScheme).
- (countdown 10)
- This only appears once
- Enter ing attempt with value 10
- Exit ing attempt with value (10
ltcontinuationgt) - The non-negative-number 10
- Exit ing attempt with value (9
ltcontinuationgt) - The non-negative-number 9
- Exit ing attempt with value (8
ltcontinuationgt) - The non-negative-number 8
- Exit ing attempt with value (7
ltcontinuationgt) - The non-negative-number 7
- Exit ing attempt with value (6
ltcontinuationgt) - The non-negative-number 6
- Exit ing attempt with value (5
ltcontinuationgt) - The non-negative-number 5
- Exit ing attempt with value (4
ltcontinuationgt) - The non-negative-number 4
18Named let expressions
- Background a named let
- (define test
- (lambda ()
- (letrec ((countdown (lambda (i)
- (if ( i 0) 'liftoff
- (begin
- (display i)
- (newline)
- (countdown (- i
1))))))) - (countdown 10))))
(define test (lambda () (letrec
((countdown (lambda (i)
(if ( i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (- i 1))))
))) (countdown 10))
))
19Named let expressions
- This is an infinite loop
- (define test
- (lambda ()
- (letrec ((countdown (lambda (i)
- (if ( i 0)
'liftoff - (begin
- (display i)
- (newline)
- (countdown
(- i 1)))) - (countdown 20))))
- (countdown 10))
- ))
(define test (lambda () (let countdown ((i
10)) (if ( i 0) 'liftoff (begin
(display i) (newline)
(countdown (- i 1)))) (countdown
20) )))
The second statement produces an infinite loop
20Coroutines
- (define hefty-computation
- (lambda (do-other-stuff)
- (letrec ((junk
- (lambda (n)
- (display "Hefty computation (a).
") - (display n)
- (newline)
- (set! do-other-stuff (call/cc
do-other-stuff)) - (display "Hefty computation (b).
") - (display n)
- (newline)
- (set! do-other-stuff (call/cc
do-other-stuff)) - (display "Hefty computation (c).
") - (display n)
- (newline)
- (set! do-other-stuff (call/cc
do-other-stuff)) - (if (gt n 0)
- (junk (- n 1)))))
- )
21Coroutines
- notationally displays a clock
- uses a named let
- (define superfluous-computation
- (lambda (do-other-stuff)
- (let loop()
- (for-each (lambda (graphic)
- (display graphic)
- (newline)
- (set! do-other-stuff (call/cc
do-other-stuff))) - '("Straight-up" "Quarter after"
"Half past" "Quarter till")) - (loop))))
- (hefty-computation superfluous-computation)
-
22Coroutines
- notationally displays a clock
- uses a letrec
- (define superfluous-computation
- (lambda (do-other-stuff)
- (letrec
- ((loop
- (lambda ()
- (for-each (lambda (graphic)
- (display
graphic) - (newline)
- (set!
do-other-stuff (call/cc do-other-stuff))) - '("Straight-up"
"Quarter after" "Half past" "Quarter till")) - (loop) this causes infinite
recursion in the local function - )))
- (loop) the single statement in the
letrec - )))
- (hefty-computation superfluous-computation)
-