>> So is the reason why #:when and #:unless can't be used the same way >> because there already exist when and unless forms? > > Are you looking for an equivalent of C's "continue" statement? I could > imagine clauses for skipping to the next iteration using the keyword > #:continue or #:next, though I have no idea if the existing loop > architecture would easily accommodate them. I don't think calling them > #:when or #:unless makes sense outside the for clauses.
Hmm, I take back my previous question, which didn't make sense (because it may result in unwanted voids). Now I'm thinking #:when and #:unless *should* be allowed in the body, for the exact reasons why #:final and #:break are allowed. But presumably there is a reason they were left out? It would be similar to C's continue, but the names should probably be the same, since they do the same thing as clause-based #:when/unless? Yes, I think the current architecture would support this change easily since it's accumulator-based. If a #:when/unless condition is true, you just call the loop with the old accumulators. I can put it in if there is agreement. > >> >> >> > Carl Eastlund >> >> > >> >> > >> >> > On Fri, Sep 6, 2013 at 2:31 PM, Stephen Chang <stch...@ccs.neu.edu> >> >> > wrote: >> >> >> >> >> >> > "Among the bodys, besides stopping the iteration and preventing >> >> >> > later >> >> >> > body evaluations, a #:break guard-expr or #:final guard-expr >> >> >> > clause >> >> >> > starts a >> >> >> > new internal-definition context." >> >> >> >> >> >> I had the same thought process as Carl. I now understand the >> >> >> behavior >> >> >> but I don't understand why it's needed? It seems kind of arbitrary >> >> >> since no other form allows multiple internal def contexts in the >> >> >> body >> >> >> like this. Is there a practical example? >> >> >> >> >> >> On Fri, Sep 6, 2013 at 12:58 PM, Carl Eastlund <c...@ccs.neu.edu> >> >> >> wrote: >> >> >> > Okay, I see what's going on here. It's very subtle though, and >> >> >> > probably >> >> >> > deserves some explanation in split-for-body's documentation. >> >> >> > >> >> >> > My first thought on seeing my non-fix version break here is that I >> >> >> > can >> >> >> > make >> >> >> > split-for-body break the same way. The problem is that my non-fix >> >> >> > separates >> >> >> > the definition of fish? from the definitions of red? and blue?, >> >> >> > which >> >> >> > it >> >> >> > depends on. I can make split-for-body separate them the same way, >> >> >> > by >> >> >> > putting a #:break or #:final clause in between the definition of >> >> >> > fish? >> >> >> > and >> >> >> > the begin form. >> >> >> > >> >> >> > The problem with doing so is a subtle point about for loops that >> >> >> > is >> >> >> > only >> >> >> > mentioned in the last sentence of the last paragraph of the >> >> >> > documentation of >> >> >> > for itself: >> >> >> > >> >> >> > "Among the bodys, besides stopping the iteration and preventing >> >> >> > later >> >> >> > body >> >> >> > evaluations, a #:break guard-expr or #:final guard-expr clause >> >> >> > starts >> >> >> > a >> >> >> > new >> >> >> > internal-definition context." >> >> >> > >> >> >> > So that's what split-for-body is preserving, the boundaries >> >> >> > between >> >> >> > internal >> >> >> > definition contexts. That's not at all what I had expected it was >> >> >> > doing; I >> >> >> > had no idea the body of a for loop constituted multiple such >> >> >> > contexts. >> >> >> > >> >> >> > Anyway, thanks for the clarification, I now understand why >> >> >> > abstractions >> >> >> > over >> >> >> > for loops need to use split-for-body. >> >> >> > >> >> >> > Carl Eastlund >> >> >> > >> >> >> > >> >> >> > On Fri, Sep 6, 2013 at 12:38 PM, Matthew Flatt >> >> >> > <mfl...@cs.utah.edu> >> >> >> > wrote: >> >> >> >> >> >> >> >> Sorry that I forgot to add the `let` while turning the code you >> >> >> >> sent >> >> >> >> into a full example. Here's another try. >> >> >> >> >> >> >> >> #lang racket/base >> >> >> >> (require (for-syntax racket/base >> >> >> >> syntax/parse >> >> >> >> syntax/for-body)) >> >> >> >> >> >> >> >> (define-syntax (for/print/good stx) >> >> >> >> (syntax-parse stx >> >> >> >> [(_ clauses . body) >> >> >> >> (with-syntax ([([pre ...] [post ...]) (split-for-body stx >> >> >> >> #'body)]) >> >> >> >> (syntax >> >> >> >> (for clauses >> >> >> >> pre ... >> >> >> >> (printf "~v\n" (let () post ...)))))])) >> >> >> >> >> >> >> >> (define-syntax-rule (for/print/fixed/not clauses pre ... result) >> >> >> >> (for clauses >> >> >> >> pre ... >> >> >> >> (printf "~v\n" (let () result)))) >> >> >> >> >> >> >> >> (for/print/fixed/not ([i 1]) >> >> >> >> (define (fish? v) (or (red? v) (blue? v))) >> >> >> >> (begin >> >> >> >> (define (red? v) (eq? v 'red)) >> >> >> >> (define (blue? v) (eq? v 'blue)) >> >> >> >> (fish? i))) >> >> >> >> >> >> >> >> At Fri, 6 Sep 2013 12:30:17 -0400, Carl Eastlund wrote: >> >> >> >> > You're proving that (let () ...) is necessary, which I have >> >> >> >> > explicitly >> >> >> >> > agreed with since the original email, but you have not yet >> >> >> >> > demonstrated >> >> >> >> > that split-for-body is necessary. Here is the fix I have >> >> >> >> > described >> >> >> >> > twice >> >> >> >> > already, now explicitly put into the define-syntax-rule >> >> >> >> > solution: >> >> >> >> > >> >> >> >> > (define-syntax-rule (for/print/fixed clauses pre .. result) >> >> >> >> > (for clauses >> >> >> >> > pre ... >> >> >> >> > (printf "~v\n" (let () result)))) >> >> >> >> > >> >> >> >> > Carl Eastlund >> >> >> >> > >> >> >> >> > >> >> >> >> > On Fri, Sep 6, 2013 at 12:25 PM, Matthew Flatt >> >> >> >> > <mfl...@cs.utah.edu> >> >> >> >> > wrote: >> >> >> >> > >> >> >> >> > > >> >> >> >> > > #lang racket/base >> >> >> >> > > (require (for-syntax racket/base >> >> >> >> > > syntax/parse >> >> >> >> > > syntax/for-body)) >> >> >> >> > > >> >> >> >> > > (define-syntax (for/print/good stx) >> >> >> >> > > (syntax-parse stx >> >> >> >> > > [(_ clauses . body) >> >> >> >> > > (with-syntax ([([pre ...] [post ...]) (split-for-body >> >> >> >> > > stx >> >> >> >> > > #'body)]) >> >> >> >> > > (syntax >> >> >> >> > > (for clauses >> >> >> >> > > pre ... >> >> >> >> > > (printf "~v\n" (let () post ...)))))])) >> >> >> >> > > >> >> >> >> > > (define-syntax-rule (for/print/bad clauses pre ... result) >> >> >> >> > > (for clauses >> >> >> >> > > pre ... >> >> >> >> > > (printf "~v\n" result))) >> >> >> >> > > >> >> >> >> > > ;; Try changing to for/print/bad: >> >> >> >> > > (for/print/good ([i 1]) >> >> >> >> > > (define (fish? v) (or (red? v) (blue? v))) >> >> >> >> > > (begin >> >> >> >> > > (define (red? v) (eq? v 'red)) >> >> >> >> > > (define (blue? v) (eq? v 'blue)) >> >> >> >> > > (fish? i))) >> >> >> >> > > >> >> >> >> > > >> >> >> >> > > At Fri, 6 Sep 2013 12:17:56 -0400, Carl Eastlund wrote: >> >> >> >> > > > Right, that's the issue with needing the (let () result) in >> >> >> >> > > > my >> >> >> >> > > > define-syntax-rule version. I still didn't need >> >> >> >> > > > split-for-body, >> >> >> >> > > > which >> >> >> >> > > > doesn't guarantee there are no definitions in the post ... >> >> >> >> > > > part. >> >> >> >> > > > All it >> >> >> >> > > > guarantees to eliminate are #:final and #:break. >> >> >> >> > > > >> >> >> >> > > > Carl Eastlund >> >> >> >> > > > >> >> >> >> > > > >> >> >> >> > > > On Fri, Sep 6, 2013 at 12:09 PM, Matthew Flatt >> >> >> >> > > > <mfl...@cs.utah.edu> >> >> >> >> > > wrote: >> >> >> >> > > > >> >> >> >> > > > > The issue is `begin` splicing. The `result` form could be >> >> >> >> > > > > a >> >> >> >> > > > > `begin` >> >> >> >> > > > > form that contains definitions that are referenced by a >> >> >> >> > > > > preceding >> >> >> >> > > > > forms. >> >> >> >> > > > > >> >> >> >> > > > > For example, given >> >> >> >> > > > > >> >> >> >> > > > > (define (fish? v) (or (red? v) (blue? v))) >> >> >> >> > > > > (begin >> >> >> >> > > > > (define (red? v) ....) >> >> >> >> > > > > (define (blue? v) ....) >> >> >> >> > > > > 5) >> >> >> >> > > > > >> >> >> >> > > > > With `begin` splicing, that turns into >> >> >> >> > > > > >> >> >> >> > > > > (define (fish? v) (or (red? v) (blue? v))) >> >> >> >> > > > > (define (red? v) ....) >> >> >> >> > > > > (define (blue? v) ....) >> >> >> >> > > > > 5 >> >> >> >> > > > > >> >> >> >> > > > > which is different than >> >> >> >> > > > > >> >> >> >> > > > > (define (fish? v) (or (red? v) (blue? v))) >> >> >> >> > > > > (let () >> >> >> >> > > > > (define (red? v) ....) >> >> >> >> > > > > (define (blue? v) ....) >> >> >> >> > > > > 5) >> >> >> >> > > > > >> >> >> >> > > > > At Fri, 6 Sep 2013 11:15:50 -0400, Carl Eastlund wrote: >> >> >> >> > > > > > Is this function ever particularly necessary? Its >> >> >> >> > > > > > intended >> >> >> >> > > > > > use >> >> >> >> > > seems to >> >> >> >> > > > > be >> >> >> >> > > > > > like so: >> >> >> >> > > > > > >> >> >> >> > > > > > (define-syntax (for/print stx) >> >> >> >> > > > > > (syntax-parse stx >> >> >> >> > > > > > [(_ clauses . body) >> >> >> >> > > > > > (with-syntax ([([pre ...] [post ...]) >> >> >> >> > > > > > (split-for-body >> >> >> >> > > > > > #'body)]) >> >> >> >> > > > > > (syntax >> >> >> >> > > > > > (for clauses >> >> >> >> > > > > > pre ... >> >> >> >> > > > > > (printf "~v/n" (let () post ...)))))])) >> >> >> >> > > > > > >> >> >> >> > > > > > That way any #:break or #:final from the body ends up >> >> >> >> > > > > > in >> >> >> >> > > > > > pre >> >> >> >> > > > > > ..., >> >> >> >> > > where >> >> >> >> > > > > the >> >> >> >> > > > > > enclosing for loop will interpret them, and post ... >> >> >> >> > > > > > will >> >> >> >> > > > > > only >> >> >> >> > > include >> >> >> >> > > > > > normal definitions and expressions. >> >> >> >> > > > > > >> >> >> >> > > > > > But it seems to me there's a much easier way that >> >> >> >> > > > > > should >> >> >> >> > > > > > always >> >> >> >> > > > > > work: >> >> >> >> > > > > > >> >> >> >> > > > > > (define-syntax-rule (for/print clauses pre ... result) >> >> >> >> > > > > > (for clauses >> >> >> >> > > > > > pre ... >> >> >> >> > > > > > (printf "~v\n" result))) >> >> >> >> > > > > > >> >> >> >> > > > > > This not only puts all #:break and #:final clauses in >> >> >> >> > > > > > pre >> >> >> >> > > > > > ..., >> >> >> >> > > > > > it >> >> >> >> > > should >> >> >> >> > > > > > guarantee result is an expression. Perhaps one should >> >> >> >> > > > > > still >> >> >> >> > > > > > write >> >> >> >> > > (let >> >> >> >> > > > > () >> >> >> >> > > > > > result) in case result is (begin defn expr), but that's >> >> >> >> > > > > > still >> >> >> >> > > > > > simpler >> >> >> >> > > > > than >> >> >> >> > > > > > using split-for-body. >> >> >> >> > > > > > >> >> >> >> > > > > > My question is -- have I overlooked some clever >> >> >> >> > > > > > subtlety >> >> >> >> > > > > > here >> >> >> >> > > > > > that >> >> >> >> > > makes >> >> >> >> > > > > > split-for-body necessary, or is it usually easier to >> >> >> >> > > > > > just >> >> >> >> > > > > > decompose >> >> >> >> > > pre >> >> >> >> > > > > ... >> >> >> >> > > > > > result rather than bothering with split-for-body? >> >> >> >> > > > > > >> >> >> >> > > > > > Carl Eastlund >> >> >> >> > > > > > _________________________ >> >> >> >> > > > > > Racket Developers list: >> >> >> >> > > > > > http://lists.racket-lang.org/dev >> >> >> >> > > > > >> >> >> >> > > > > >> >> >> >> > > >> >> >> >> > > >> >> >> >> >> >> >> > >> >> >> > >> >> >> > _________________________ >> >> >> > Racket Developers list: >> >> >> > http://lists.racket-lang.org/dev >> >> >> > >> >> >> >> >> > >> >> >> > >> > _________________________ Racket Developers list: http://lists.racket-lang.org/dev