I've ported srfi-154 and srfi-155 reference implementations to Gauche and played with it to see performance implications, and noticed a peculiar behavior. It might be something I'm doing wrong.
I use these infinite stream of integers and taking first n elements from it:
(let next ((n 0))
(delay (cons n (next (+ n 1))))))
(define (xtake stream n)
(let loop ((s stream) (r '()) (n n))
(if (= n 0)
(loop (cdr (force s))
(cons (car (force s)) r)
(- n 1)))))
While running with various n with fresh streams, I noticed it was taking O(n^2) time.
After some digging, I see the cause.
(delay (cons n (next (+ n 1))))
is expanded to:
(let ((dynamic-extent (current-dynamic-extent)))
(let ((forcing-extent (current-dynamic-extent)))
(parameterize ((current-forcing-extent forcing-extent))
(cons n (next (+ n 1)))))))))
When it is forced, the inner expression (cons n (next (+ n 1))) is evaluated with the dynamic extent
which is the extent 'delay' is evaluated *plus* the extent added by parameterizing current-forcing-extent. The call to next calls delay again, which captures this enhanced dynamic extent.
When the new promise is evaluated, the dynamic extent is further extended by yet another parameterization of current-forcing-extent, and so on.
Since the calls of force in xtake happens outside of those extended dynamic extent, every force executes before and after thunks of parameterization of current-forcing-extent, which gets longer as the stream unfolded.