Call/cc and mutation-friendly fold Marc Nieper-Wißkirchen (11 Aug 2022 08:15 UTC)
Re: Call/cc and mutation-friendly fold Marc Nieper-Wißkirchen (14 Aug 2022 19:27 UTC)
Re: Call/cc and mutation-friendly fold Marc Nieper-Wißkirchen (28 Oct 2022 11:13 UTC)

Re: Call/cc and mutation-friendly fold Marc Nieper-Wißkirchen 28 Oct 2022 11:13 UTC

I am still waiting to hear from the SRFI 127 and SRFI 158 authors
about this.  Can this be addressed and the specs and implementation be
improved? The code is given in my previous post.

There's no hurry; I don't want that this issue falls into oblivion.

Am So., 14. Aug. 2022 um 21:27 Uhr schrieb Marc Nieper-Wißkirchen
<xxxxxx@gmail.com>:
>
> Here is some example code (for Chibi-Scheme) to experiment with.  The naive versions (the specification of generator-fold in SRFI 158 and the recipe for a space-efficient lseq-fold in SRFI 127) fail as expected.
>
> (import (scheme base)
>         (scheme write)
>         (srfi 1)
>         (srfi 127)
>         (srfi 158)
>         (chibi test))
>
> (define (run-fold folder seq)
>   (let ((k #f))
>     (folder
>      (lambda (el acc)
>        (when (procedure? k)
>          (let ((c k))
>            (set! k #t)
>            (c)))
>        (unless k
>          (call/cc (lambda (c) (set! k c))))
>        (cons el acc))
>      '() seq)))
>
> (test "list fold"
>       '(3 2 1)
>       (run-fold fold '(1 2 3)))
>
> (test "naive generator fold"
>       '(3 2 1)
>       (run-fold generator-fold (generator 1 2 3)))
>
> (define (lseq . el*)
>   (generator->lseq (apply generator el*)))
>
> (define (lseq-fold proc seed . lseq*)
>   (apply generator-fold proc seed (map lseq->generator lseq*)))
>
> (test "naive lseq fold"
>       '(3 2 1)
>       (run-fold lseq-fold (lseq 1 2 3)))
>
> (define (*lseq-fold proc seed . lseq*)
>   (let f ((seed seed) (lseq* lseq*))
>     (if (any null? lseq*)
>         seed
>         (f (apply proc (append (map lseq-first lseq*)
>                                (list seed)))
>            (map lseq-rest lseq*)))))
>
> (test "corrected lseq fold"
>       '(3 2 1)
>       (run-fold *lseq-fold (lseq 1 2 3)))
>
> (define (*generator-fold proc seed . gen*)
>   (apply *lseq-fold proc seed (map generator->lseq gen*)))
>
> (test "corrected generator fold"
>       '(3 2 1)
>       (run-fold *generator-fold (generator 1 2 3)))
>
>
> Am Do., 11. Aug. 2022 um 10:15 Uhr schrieb Marc Nieper-Wißkirchen <xxxxxx@gmail.com>:
>>
>> (CC to SRFI 231 mailing list because the issue came up there most recently.)
>>
>> As `generator-fold` is the universal adapter from the impure, imperative world of generators to the pure functional subset of Scheme, I think it is important that it still works correctly in the presence of call/cc (and outside mutation).
>>
>> The most naive correct (in the sense of the above) implementation of generator-fold would therefore have to be
>>
>> (define generator-fold
>>   (lambda (proc . gen*)
>>     (apply fold proc (map generator->list gen*))))
>>
>> A more space-efficient implementation (at least, when multiple threads are not involved) would be
>>
>> (define generator-fold
>>   (lambda (proc . gen*)
>>     (apply lseq-fold proc (map generator->lseq gen*))))
>>
>> For that, lseq-fold with call/cc-correct semantics should be added to SRFI 127.
>>
>> The most efficient implementation would need a way to detect whether a continuation is captured in the dynamic extent of `proc`.  (There should probably be a SRFI for that because this cannot be done portably without redefining call/cc.)  As long as no continuation is captured, the naive implementation would be used.
>>