[comp.lang.scheme] bindings captured by continuations

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