For* remains looping when an inner suequence already is empty

Consider:

#lang racket/base
(define r '())
(time (for* ((i (in-range 10000000)) (k (in-list r))) (writeln (list i k))))
(time (for* ((i (in-range 1       )) (k (in-list r))) (writeln (list i k))))

Produces:

cpu time: 31 real time: 39 gc time: 0
cpu time: 0 real time: 0 gc time: 0

for* keeps looping on an outer sequence when an inner sequence is empty and hence the outer loop just keeps looping doing nothing. I think that when an inner sequence is empty (or becomes empty due to a side effect), the loops on the outer sequences should be halted immediately. Would it be difficult to adapt for* and its variants such as to escape from the whole for-form when an empty inner sequence is encountered? I think it is not difficult. I have looked into the source code of for* and its variants, but this code is rather complicated, so complicated, that i would not know how to implement my wish within this code.
Thanks, Jos

It appears to me that your outer loop could be drawing from an effectful sequence. In this case, it would be important to continue to draw all of the elements from the outer sequence, no?

1 Like

Now it's compiled to (after untranslating some pars from Chez Scheme to Racket)

($app/value check-range-generic 'in-range 0 10000000 1)
(letrec ([loop (lambda (pos)
                 (if (unsafe-fx< pos 10000000)
                   (begin
                     ($app/value check-list '())
                     (loop (unsafe-fx+ 1 pos)))
                   (values)))])
  (loop 0))

where $app(valueis used internally to ensure the function will return a single value and not capture continuations.

It would be very nice if check-listwhere inlined and eliminated by the compiler. I'm not sure if the problem is that check-list in an internal function or Chez Scheme does not inline functions applied with $app/value. So this call is opaque, and prevents any interesting elimination.

After magically eliminating it, it's very difficult to detect that the loop is doing nothing and will stop eventually. I think it's possible some day, but it's not easy. (And there are some weird corner cases, for example with flonums (in-range 1e20 1e21 1.) should not finish.)

Thanks, you convinced me that in some cases the outer loop must keep running and that it would be very hard and in general even impossible for a syntax transformer or compiler to predict whether or not more inner cycles will follow.