;;6.001 Spring '00 Sections 7 & 8 Prof. Albert R. Meyer ; CALL-WITH-CURRENT-CONTINUATION EXAMPLES #| What is the point of Scheme's CALL-WITH-CURRENT-CONTINUATION (aka CALL-CC)? The short answer is that all of the flow-of-control operations typically found in programming languages can be defined using CALL-CC, so by having this one special procedure, Scheme has no need to include other flow-of-control operations. For example, suppose we want a procedure like Scheme's ERROR, but which returns to Scheme's READ-EVAL-PRINT-LOOP instead of returning to THE DEBUGGER: |# (define (return-to-repl val) 'dummy) (call-with-current-continuation (lambda (send-to-repl) (set! return-to-repl send-to-repl))) (define (add a b) (if (and (number? a) (number? b)) (+ a b) (return-to-repl (list "error in ADD: nonnumber argument:" a b)))) (* 3 (add 1 #f)) ;Value: ("error in ADD: nonnumber argument:" 1 #f) #| A more informative example shows how to use CALL-CC to define an ESCAPE procedure which returns a value to a designated calling procedure. This is more general and useful than just returning a value to Scheme's REPL: |# ;RECURSIVE-LAST-EVEN returns the LAST even number in a list, INTS, ;of integers. It returns #f if there is no even number. (define (recursive-last-even ints) (and (pair? ints) (or (recursive-last-even (cdr ints)) (let ((first-num (car ints))) (and (even? first-num) first-num))))) (trace-exit recursive-last-even) ;Value: #[unspecified-return-value] ;Notice that the last even number, 8, gets returned to each of the ;preceding recursive calls: (recursive-last-even '(1 3 5 6 7 8 9)) [#f <== #[compound-procedure 19 recursive-last-even] Args: #f] [#f <== #[compound-procedure 19 recursive-last-even] Args: (9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (8 9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (7 8 9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (6 7 8 9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (5 6 7 8 9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (3 5 6 7 8 9)] [8 <== #[compound-procedure 19 recursive-last-even] Args: (1 3 5 6 7 8 9)] ;Value: 8 ;On the other hand, writing LAST-EVEN using call-cc allows the procedure ;to escape with the answer as soon as it is found: (define (last-even ints) (call-with-current-continuation (lambda (escape-with-last-even-value) (define (aux nums) (if (null? nums) 'return-anything (begin (aux (cdr nums)) ;BEGIN works because the call to AUX only returns ;a value if it fails to find an even number, in ;which case its value can be ignored (let ((first-num (car nums))) (if (even? first-num) (escape-with-last-even-value first-num) ;escape with the answer FIRST-NUM "just return"))))) ;otherwise return (trace-exit aux) ;tracing shows that AUX escapes with the last even number, if any (aux ints) ;this call returns only if INTS contains no even number #f))) ;so in that case, return #f ;Now notice AUX stops returning as soon as it finds the last even number: (last-even '(1 3 5 6 7 8 9)) #| [return-anything <== #[compound-procedure 18 aux] Args: #f] ["just return" <== #[compound-procedure 18 aux] Args: (9)] |# ;Value: 8 ;AUX returns values to all the recursive calls only when there is ;no even number in the list: (last-even '(1 3 5 7 9)) #| [return-anything <== #[compound-procedure 21 aux] Args: #f] ["just return" <== #[compound-procedure 21 aux] Args: (9)] ["just return" <== #[compound-procedure 21 aux] Args: (7 9)] ["just return" <== #[compound-procedure 21 aux] Args: (5 7 9)] ["just return" <== #[compound-procedure 21 aux] Args: (3 5 7 9)] ["just return" <== #[compound-procedure 21 aux] Args: (1 3 5 7 9)] ;Value: #f |#