[racket-dev] Short-circuiting comprehensions

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Sep 14 16:35:44 EDT 2012

I like most of that and don't object to the rest, except for leaving out a
version of #:break-unless.  Especially because "break" is already a
negative word.  Just like #:unless (bad?) is more natural than #:when (not
(bad?)), #:<something> (ok-to-continue?) is more natural than #:break (not
(ok-to-continue?)).  I'd suggest "#:continue", but in C-like languages I
believe that means something different.

Actually, we could make the whole thing more positive (or, ironically, less
negative) by going with #:do-while and #:do-until, something like that.  It
brings back the nicely mnemonic "while" and "until", is hard to confuse
with "when" and "unless", and "do" isn't that much extra to read.  And it's
positive, so it doesn't reverse the meaning of the second word.

Carl Eastlund

On Fri, Sep 14, 2012 at 4:25 PM, Matthew Flatt <mflatt at cs.utah.edu> wrote:

> At Fri, 14 Sep 2012 15:30:22 -0400, Eli Barzilay wrote:
> > Four hours ago, Matthew Flatt wrote:
> > >
> > > Also, I think the names `#:while' and `#:until' are too close to
> > > `#:when' and `#:unless'. I suggest `#:break-when' and `#:break-unless'.
> > > Compare:
> > >
> > >  > (for*/list ([j 2] [i 10] #:when (i . < . 5)) i)
> > >  '(0 1 2 3 4 0 1 2 3 4)
> > >  > (for*/list ([j 2] [i 10] #:break-unless (i . < . 5)) i)
> > >  '(0 1 2 3 4)
> > >
> > > I imagine that `#:break-when' and `#:break-unless' are allowed among
> > > the clauses much like `#:when' and `#:unless', but also allowed at the
> > > end of the body. Is that what you had in mind?
> >
> > Sorry for the bike-shedding, but to me that `#:break-unless' is even
> > harder to read than `#:until'.  Possible explanation: "break unless"
> > makes me parse two words and figure out how they combine, and "while"
> > is something that I know without doing so.
>
> After trying out various options, I agree that `break-when' is too many
> words. I'm currently trying just `break' and dropping `break-unless',
> and that feels better.
>
> At Fri, 14 Sep 2012 11:49:20 -0400, Carl Eastlund wrote:
> > I agree that #:while and #:until are easily confused with #:when and
> > #:unless.  I slightly prefer #:stop- to #:break- as a prefix here, it
> seems
> > a more natural word.
>
> I like "break" because it goes with "for", it avoids potential
> confusion with "stop" in `stop-after' and `stop-before', and it is more
> clearly different from "final" (which is used below).
>
> > I like the idea of allowing these clauses at the end
> > of the body to give a notion of stopping after the current iteration.
>
> It turns out that allowing `#:break' at the very end of the body causes
> problems with scope and composition.
>
> Imagine trying to implement `for/set' by wrapping its body in an
> expansion to `for/fold'. Maybe you can look from the end of the body
> and skip back over `#:break' clauses, but now imagine that the last
> form before `break' expands to a combination of a definition and an
> expression, and the `#:break' clause wants to refer to the identifier
> that is bound in the expansion. We could probably make all that work
> with `local-expand' and internal-definition contexts, but that gets
> complicated.
>
> Requiring an expression at the end of a `for' body --- while allowing
> `#:break' clauses otherwise interspersed in the body --- avoids
> composition and scope problems. Macros still have to do a little work
> to juggle `#:break' clauses, but a `split-for-body' helper function is
> straightforward to use.
>
> Meanwhile, to support breaking after the current element, I'm trying
> out `#:final'. A `#:final' clause is like `#:break', except that it
> ends the loop after the next run of the body. (The two kinds of clauses
> closely related to `stop-before' and `stop-after'.)
>
> > (for/list ([i 10]) #:break (= i 2) i)
> '(0 1)
> > (for/list ([i 10]) #:final (= i 2) i)
> '(0 1 2)
>
> > (for ([book '("Guide" "Story" "Reference")]
>         #:break (equal? book "Story")
>         [chapter '("Intro" "Details" "Conclusion")])
>     (printf "~a ~a\n" book chapter))
> Guide Intro
> Guide Details
> Guide Conclusion
>
> > (for* ([book '("Guide" "Story" "Reference")]
>          [chapter '("Intro" "Details" "Conclusion")])
>     #:break (and (equal? book "Story")
>                  (equal? chapter "Conclusion"))
>     (printf "~a ~a\n" book chapter))
> Guide Intro
> Guide Details
> Guide Conclusion
> Story Intro
> Story Details
>
> > (for* ([book '("Guide" "Story" "Reference")]
>          [chapter '("Intro" "Details" "Conclusion")])
>     #:final (and (equal? book "Story")
>                  (equal? chapter "Conclusion"))
>     (printf "~a ~a\n" book chapter))
> Guide Intro
> Guide Details
> Guide Conclusion
> Story Intro
> Story Details
> Story Conclusion
>
> > (for ([book '("Guide" "Story" "Reference")]
>         #:final (equal? book "Story")
>         [chapter '("Intro" "Details" "Conclusion")])
>     (printf "~a ~a\n" book chapter))
> Guide Intro
> Guide Details
> Guide Conclusion
> Story Intro
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20120914/b7bb0692/attachment-0001.html>

Posted on the dev mailing list.