[racket-dev] for loops with interleaved escape continuations

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Tue Jul 1 14:51:55 EDT 2014

In principle I like this #:ec idea, but I would feel more comfortable if you explored the whole range of for loops and their interactions with this new feature. -- Matthias

On Jun 28, 2014, at 6:54 AM, Jay Kominek wrote:

> On Fri, Jun 27, 2014 at 8:40 PM, J. Ian Johnson <ianj at ccs.neu.edu> wrote:
>> One is that #:when in for-clauses allows you to skip iterations, but you want it in the body. This is a cosmetic difference that you can get around by doing #:when (begin imperative-stuff-before-guard guard). If you want ecs to escape an entire for loop, that's what #:break is for. If you want ecs to escape even more for loops, well, that is an unplanned but a possibly useful feature for nested for loops.
> Yes, #:when gets frustratingly close, but if
> imperative-stuff-before-guard does something expensive (fetches the
> ith web page, or what have you), I've got to repeat it in the body if
> I actually want to use the value. Same issue with #:break and all the
> other guards.
> If I end up wanting #:when, #:break, and the body of the expression to
> all make use of some expensive value, I'm stuck reproducing it. (Or
> setting up some previous loop to make a bunch of promises that I can
> force... bleh.)
> Would I have more luck selling folks on some sort of #:let [id
> val-expr] construct that could mix in with the sequences? That'd get
> me most of what I was going for, and it is probably(?) a lot more
> obvious how it should behave.
>> The other is that this is not Rackety and thus not natively supported for the same reason there are no "return" statements. The for macros are so much more than Python's for - they can produce values. Don't throw everything into the void :)
> Sorry, I should've put more than a moment's effort into my example. I
> specifically tried to ensure that this can do more than Python's break
> & continue! In fact, this allows poor boring "for" who normally
> produces nothing but void to produce a useful value. Here are some
> more examples, again contrived because I'm trying to keep them short,
> but hopefully making more apparent the advantage over simple break &
> continue:
> (for (#:ec break
>      [x (in-range 0 10)])
>  (when    (= x 2)
>    (break "found it!"))
>  (printf "~a~n" x))
> 0
> 1
> "found it!"
> (for/fold ([x 0] [y 0])
>          (#:ec break
>       [i (in-range    0 10)]
>           #:ec    continue)
>  (when (= i 3)
>    (continue (+ x 1000) (+ y 1000)))
>  (when    (= i 7)
>    (break (exact->inexact x) y))
>  (values (add1 x) (add1 y)))
> 1006.0
> 1006
> The inner escape continuation passes its values along to the next
> iteration, while the outer one can return values for the entire
> expression. And of course, it can be interleaved between sequences,
> just like #:when and friends.
> I was allowing the use of the continuations without arguments so that
> there'd be a more obvious translation from languages with wimpy
> control statements, but they raise the issue of what values should be
> used by default.
> (And to reiterate the current inadequacies, it doesn't behave at all
> properly with for/list, for/vector or for/set.)
> Thanks for looking.
> -- 
> Jay Kominek
> _________________________
>  Racket Developers list:
>  http://lists.racket-lang.org/dev

Posted on the dev mailing list.