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] |
| 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)))