This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: searching an explanation: call/cc and 'do' strangeness


| We have stumpled across some rather strange looking behaviour when
| trying to combine `do' and `call/cc'. I suspect the problem is related
| to this paragraph from R4RS:
| 
|      `Do' expressions are evaluated as follows: The <init> expressions
|      are evaluated (in some unspecified order), the <variable>s are
|      bound to fresh locations, the results of the <init> expressions ...
|               ^^^^^^^^^^^^^^^
| 
| but if anybody can explain precisely (or even vaguely :-) what is
| going on in the following code, we would appreciate the enlightment.
| 
| The example may seem a bit complex but has been extracted from the
| application we are currently working with. The idea is to control a
| walk of a datastructure using a kind of co-routine style to control
| the communication between the maintainer of the datastructure and the
| client doing the walk.
| 
| The "server" is implemented by the following function:
| 
|     (define invocation-demo #f)
| 
|     (define scopeWalkDemo (lambda (continuation)
|       (let ((result #f))
| 	(set! invocation-demo 
| 	      (if (not continuation)
| 		  (call-with-current-continuation invocation-demo)
| 		  (call-with-current-continuation
| 		   (lambda (found)
| 		     (let ((l (list 'cow 'horse 'pig )))
| 		       (do ((i 0 (+ i 1)))
| 			   ((= i (length l)))
| 			 (set! result (list-ref l i))
| 			 (call-with-current-continuation found))
| 		       (set! result #f))))))
| 	result)))
| 
| which generates a list (containing the symbols cow, horse and pig) and
| returns these by subsequent calls of `scopeWalkDemo' as in the
| following session:
| 
|     guile> (scopeWalkDemo #t)
|     cow
|     guile> (scopeWalkDemo #f)
|     horse
|     guile> (scopeWalkDemo #f)
|     pig
|     guile> (scopeWalkDemo #f)
|     #f
| 
| Now, suppose I want fill the symbols into a vector using a `do' loop,
| I could something like this:
| 
|     guile> (define v-demo (make-vector 3))
|     guile> 
|     (do ((j 0) (cont #t) (tmp #f))	
| 	((>= j 3)) 
|       (display (list cont j v-demo))(newline)
|       (set! tmp (scopeWalkDemo cont))
|       (vector-set! v-demo j tmp)
|       (set! j (1+ j))
|       (set! cont #f))
|     (#t 0 #(#<unspecified> #<unspecified> #<unspecified>))
|     (#f 1 #(cow #<unspecified> #<unspecified>))
|     (#f 2 #(cow horse #<unspecified>))
|     guile> v-demo
|     #(cow horse pig)
| 
| But if I try to update `j' using a <step> clause, I get the following:
| 
|     guile> (define v-demo (make-vector 3))
|     guile> 
|     (do ((j 0 (1+ j))(cont #t)(tmp #f))	
| 	((>= j 3)) 
|       (display (list cont j v-demo))(newline)
|       (set! tmp (scopeWalkDemo cont))
|       (vector-set! v-demo j tmp)
|       (set! cont #f))
|     (#t 0 #(#<unspecified> #<unspecified> #<unspecified>))
|     (#f 1 #(cow #<unspecified> #<unspecified>))
|     (#f 1 #(horse #<unspecified> #<unspecified>))
|     (#f 1 #(pig #<unspecified> #<unspecified>))
|     (#f 1 #(#f #<unspecified> #<unspecified>))
|     ERROR: In expression (@call-with-current-continuation proc):
|     ERROR: Wrong type to apply: #f
|     ABORT: (misc-error)
|     guile> v-demo
|     #(#f #<unspecified> #<unspecified>)
| 
| 
| Or if I move the scopeWalkDemo into the vector-set! expression I get
| the following:
| 
|     guile> (define v-demo (make-vector 3))
|     guile> 
|     (do ((j 0) (cont #t))	
| 	((>= j 3)) 
|       (display (list cont j v-demo))(newline)
|       (vector-set! v-demo j (scopeWalkDemo cont))
|       (set! j (1+ j))
|       (set! cont #f))
|     (#t 0 #(#<unspecified> #<unspecified> #<unspecified>))
|     (#f 1 #(cow #<unspecified> #<unspecified>))
|     (#f 2 #(horse #<unspecified> #<unspecified>))
|     guile> v-demo
|     #(pig #<unspecified> #<unspecified>)
| 
| 
| So what is going on. Is our usage of call/cc in error, is this a bug
| with `do' or perhaps just a feature of the excessive powers of
| call/cc?

It's the usage of call/cc.  It's capturing the current bindings,
but the values in the bindings can be changed within the continuation
loop.

consider:

(define cont #f)
(let ((i 0))
  (let loop ()
    (display i)
    (newline)
    (if cont
	(cont #f))
    (call-with-current-continuation (lambda (c)
				      (set! cont c)))
    (set! i (+ i 1))
    (loop)))
 

(define cont #f)
(let loop ((i 0))
  (display i)
  (newline)
  (if cont
      (cont #f))
  (call-with-current-continuation (lambda (c)
				    (set! cont c)))
  (loop (+ i 0)))