Yes, I agree to both points.  It's up to Arthur if a PFN is appropriate:
I"m in favor of having one.  Can you draft it?  (If Arthur is not okay with
it, it will go to Committee C.)

On Sat, Feb 11, 2023 at 7:05 PM Shiro Kawai <[email protected]> wrote:

> Good point.
>
> It is certainly undesirable that merely calling lseq-for-each forces all
> elements in the argument, and I'm for reimplementing it.
>
> Regarding the order of effects, I have an opinion.  The design choice of
> lseq is to loosen the strict laziness to get efficiency.  Srfi-127 is
> inspired by Gauche's lseq, which in turn is inspired by Clojure's seq.  I
> believe Clojure may realize seq's elements in a chunk, e.g. 32 elements at
> a time, at least in some situations.  So you shouldn't rely on the timing
> of evaluation anyway; all that's guaranteed is that the data is available
> by the time you accessed it, and the whole thing runs in a bounded space if
> you don't keep the previous elements.  I think lseq should be used in the
> same way, that is, you shouldn't rely on that (lseq-for-each write-char
> chars) prints "read write read write ..."; it may print "read read write
> write read read write ...".   But of course, you should be able to pass an
> infinite lseq to lseq-for-each and expect proc to be definitely called.
>
> Can this kind of semantic refinement go into post finalization notes?
>
> --shiro
>
>
>
>
> On Sat, Feb 11, 2023 at 8:12 AM Wolfgang Corcoran-Mathe <[email protected]>
> wrote:
>
>> Hi,
>>
>> The sample implementation of lseq-for-each has some surprising
>> behavior. Here’s the implementation:
>>
>>     (define (lseq-for-each proc . lseqs)
>>       (apply for-each proc (map lseq-realize lseqs)))
>>
>> Rather than traversing the lseqs and applying proc to their cars
>> at each step, it fully forces them before traversing. There are
>> two problems here.
>>
>> 1. Fully forcing the lseqs wastes space. A major reason to use
>> lseqs is to avoid building huge lists. Thus, ignoring proc’s needs,
>> lseq-for-each should operate in constant space.
>>
>> 2. Effects occur in an unexpected order. This is more interesting.
>> Forcing the cdr of an lseq can have side effects, as can calling proc;
>> indeed, proc is called for its side effects. When do these different
>> effects occur? Consider this common kind of I/O stream:
>>
>>     (define chars (generator->lseq read-char))
>>
>> Calling ‘lseq-cdr’ on chars causes a side effect: reading a character.
>> Now, combine this with an output procedure:
>>
>>     (lseq-for-each write-char chars)
>>
>> The read and write effects could occur in (at least) two different
>> orders:
>>
>>     read
>>     write
>>     read
>>     write
>>     ...
>>
>> or
>>
>>     read
>>     read
>>     ...
>>     read
>>     write
>>     write
>>     ...
>>     write
>>
>> The SRFI doesn’t tell us which to expect, but the latter, “clustered”
>> pattern is bad. It will sponge up all available input before producing
>> any output, hanging the program if ‘read-char’ blocks. “Interleaving”
>> the effects, as in the first pattern, avoids these problems.
>>
>> ***
>>
>> The fix for both problems is simple: just implement ‘lseq-for-each’
>> directly. I’ll send a pull request with this implementation shortly.
>>
>> I think a note about effect order should also be added to the
>> ‘lseq-for-each’ specification. Perhaps this: “If forcing the cdr of
>> lseq entails side effects, then those effects are interleaved with
>> the effects of calling proc.”
>>
>> Regards,
>>
>> Wolf
>>
>> --
>> Wolfgang Corcoran-Mathe  <[email protected]>
>>
>

Reply via email to