[racket-dev] for loops with interleaved escape continuations
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