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