[racket-dev] for loops with interleaved escape continuations

From: Sam Tobin-Hochstadt (samth at cs.indiana.edu)
Date: Tue Jul 1 15:09:00 EDT 2014

I think this is a good idea, and something that I've wanted for a long
time. But there are ways to make it much better, and generalize to all
loops.

First, recognize that a `for/...` loop is really a recursive function,
which is passing along a bunch of arguments. In this setting,
`continue` means to make a new recursive call with the same arguments
as last time, and `break` means to exit the loop with the current
values of the arguments.

One solution, therefore, is to just bind `break` and `continue`
identifiers as specified to functions that just make these calls. This
works perfectly if you call break/continue in tail position with
respect to the loop body, but does weird things otherwise.

Another solution is to bind break and continue to function which use
let/ec to jump out of whatever context they're in inside the loop
body, and then make the appropriate transition to the next
iteration/the end of the loop.

A third solution is to have explicit keywords that can appear in the
loop body, such as #:break and #:continue, and which are transformed
to make the appropriate recursive call. This avoids both the
continuation capture and the potential strange behavior when called in
non-tail position.

A fourth solution, not currently implementable, would be to take
solution 1, plus a way of statically erroring when certain expressions
didn't appear in tail position wrt another expression.

I think 4 would be my preference, but of the other three I'm unsure.

Sam

On Fri, Jun 27, 2014 at 11:15 PM, Jay Kominek <kominek at gmail.com> wrote:
> I've been converting a bunch of Python to Racket lately, and I have a
> lot of loops that use break and continue. I end up turning them into:
>
> (let/ec break
>   (for (...)
>     (let/ec continue
>       ; do some work
>       (when this-iteration-isn't-what-i-want
>         (continue))
>       ; do more expensive work
>       (when found-what-i-want
>         (break what-i-want)))))
>
> I thought it would be nice if the let/ec's could be integrated with
> for, so that you could instead write:
>
> (for (#:ec break
>        ...
>        #:ec continue)
>       ; ...same as above...
>
> In an attempt to help convey the behavior I want, I threw this patch together:
>
> https://github.com/jkominek/racket/commit/b291a0b994c679445b3210bd3efba8c6cea867e4
>
> I feel it behaves reasonably when using for and for/fold, but for/list
> doesn't behave in any way I'd hope for.
>
> Ideally somebody who understands for's implementation will agree that
> this is a great idea, and go make it all work nicely. :) Failing that
> I'm open to suggestions for how to make it behave better, in a fashion
> which would make it appropriate for inclusion.
>
> --
> Jay Kominek
> _________________________
>   Racket Developers list:
>   http://lists.racket-lang.org/dev

Posted on the dev mailing list.