> "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