[plt-scheme] understanding make-do-sequence

From: Dave Herman (dherman at ccs.neu.edu)
Date: Sun Apr 13 15:48:05 EDT 2008

It appears that `make-do-sequence' avoids applying the first procedure 
(the pos->element one) if certain other procedures indicate the sequence 
is finished. This is important to the client in the case where that 
procedure has side effects.

Consider a sequence generator `in-port-until':

     ;; a * (a -> b1 .. bn) (a -> boolean) -> (sequenceof b1 .. bn)
     (define (in-port-until port reader done?)
       (make-do-sequence (lambda ()
                           (values reader
                                   (lambda (port) port)
                                   (lambda (port)
                                     (not (done? port)))
                                   (lambda (port . values) #t)))))

and a use case like:

     > (define p (open-input-string "xxxxy"))
     > (define (no-more-xs? port)
         (not (char=? (peek-char port) #\x)))
     > (for/list ([x (in-port-until p read-char no-more-xs?)])
     (#\x #\x #\x #\x)
     > (read-char p)

That last line is the critical one: if `in-port' had caused `read-char' 
to be called the extra time, it would've silently eaten the last #\y 
char, and the last line would've returned #<eof>.

This seems pretty subtle. I don't know if a cleaner API is possible, but 
it at least bears documenting exactly when the pos->element will and 
won't be applied.


Posted on the users mailing list.