carr%jensen.utah.edu@cs.utah.edu (Harold Carr) (04/19/91)
My understanding of a continuation is that is should capture the data and control at the point of call/cc and bind that to the given lambda's parameter. It is clear that any variables within the lambda given to call/cc but bound outside are closed and therefore any changes to the values of those bindings by others sharing the closed variables are visible. However, it seems to me, that bindings/values created before the call/cc and captured by it, should not see any side effects done *after* the continuation point when that continuation is used again. An example should make this clear. In elk: (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (cmaker) ==> 1 (cont1 'dummy) ==> 2 (cont1 'dummy) ++> 3 and so on Is this the correct behavior? If not, what should be. The call to CMAKER should definitely print 1, but it seems that the first call to CONT1 should also print 1. References to applicable papers would be appreciated. Thanks, Harold
matthias@leto.rice.edu (Matthias Felleisen) (04/20/91)
Bob Hieb and I developed a calculus of Scheme, very much along the lines of Church's lambda calculus, based on which we can manipulate the program text of a Scheme program to explain its results and effects. Translated into Scheme syntax and conventions, your program would evaluate as sketched below. Hope that helps -- Matthias Felleisen {Felleisen, M. and R. Hieb}. The revised report on the syntactic theories of sequential control and state. Technical Report 100, Rice University, June 1989. {\it Theor. Comput. Sci.}, 1991, to appear. A program is a sequence of defines plus an expression (or several). The define's represents the "store", the context of the leftmost-outermost redex the "continuation". { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (cmaker)} --> deref cmaker { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))} --> make "count" global (rename if necessary) { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))} --> deref "count" { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin (if (= 0 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))} --> compare (built-in rules about =) { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin (if #t (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))} --> if test for #t { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin (call-with-current-continuation (lambda (cont) (set! cont1 cont))) (set! count (+ count 1)) (newline) (display count))} --> grab the continuation: the rest of the begin { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin ((lambda (cont) (set! cont1 cont)) (lambda (arg) (stop ; ignore current stack (begin arg (set! count (+ count 1)) (newline) (display count))))) (set! count (+ count 1)) (newline) (display count))} --> beta-value { (define cont1) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin (set! cont1 (lambda (arg) (stop ; ignore current stack (begin arg (set! count (+ count 1)) (newline) (display count))))) (set! count (+ count 1)) (newline) (display count))} --> store the continuation in "cont1" { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 0) (begin '**void** ; or whatever set! returns (set! count (+ count 1)) (newline) (display count))} --> bump "count" { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1) (begin '**void** ; or whatever set! returns (newline) (display count))} --> print newline { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1) (begin '**void** ; or whatever set! returns (display count))} |> newline; --> deref "count" { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1) (begin (display 1))} |> newline; --> print 1 { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1)} |> newline; 1 ;; return ;; now, continuing: { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1) (cont1 'dummy)} --> { (define cont1 (lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count))))) (define (cmaker) (let ((count 0)) (if (= count 0) (call-with-current-continuation (lambda (cont) (set! cont1 cont)))) (set! count (+ count 1)) (newline) (display count))) (define count 1) ((lambda (arg) (stop (begin arg (set! count (+ count 1)) (newline) (display count)))) 'dummy)} --> etcetera as above