<div dir="ltr"><div><div><div>Okay, I see what's going on here. It's very subtle though, and probably deserves some explanation in split-for-body's documentation.<br><br></div>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.<br>
<br>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:<br><br> "Among the <span class="">body</span>s, besides stopping the
iteration and preventing later <span class="">body</span> evaluations, a
<span class="">#:break</span><span class=""> </span><span class="">guard-expr</span> or <span class="">#:final</span><span class=""> </span><span class="">guard-expr</span>
clause starts a new internal-definition context."<br><br></div>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.<br>
<br></div>Anyway, thanks for the clarification, I now understand why abstractions over for loops need to use split-for-body.<br></div><div class="gmail_extra"><br clear="all"><div>Carl Eastlund</div>
<br><br><div class="gmail_quote">On Fri, Sep 6, 2013 at 12:38 PM, Matthew Flatt <span dir="ltr"><<a href="mailto:mflatt@cs.utah.edu" target="_blank">mflatt@cs.utah.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Sorry that I forgot to add the `let` while turning the code you sent<br>
into a full example. Here's another try.<br>
<div class="im"><br>
#lang racket/base<br>
(require (for-syntax racket/base<br>
syntax/parse<br>
syntax/for-body))<br>
<br>
(define-syntax (for/print/good stx)<br>
(syntax-parse stx<br>
[(_ clauses . body)<br>
(with-syntax ([([pre ...] [post ...]) (split-for-body stx #'body)])<br>
(syntax<br>
(for clauses<br>
pre ...<br>
(printf "~v\n" (let () post ...)))))]))<br>
<br>
</div>(define-syntax-rule (for/print/fixed/not clauses pre ... result)<br>
(for clauses<br>
pre ...<br>
(printf "~v\n" (let () result))))<br>
<br>
(for/print/fixed/not ([i 1])<br>
<div class="im HOEnZb"> (define (fish? v) (or (red? v) (blue? v)))<br>
(begin<br>
(define (red? v) (eq? v 'red))<br>
(define (blue? v) (eq? v 'blue))<br>
(fish? i)))<br>
<br>
</div><div class="HOEnZb"><div class="h5">At Fri, 6 Sep 2013 12:30:17 -0400, Carl Eastlund wrote:<br>
> You're proving that (let () ...) is necessary, which I have explicitly<br>
> agreed with since the original email, but you have not yet demonstrated<br>
> that split-for-body is necessary. Here is the fix I have described twice<br>
> already, now explicitly put into the define-syntax-rule solution:<br>
><br>
> (define-syntax-rule (for/print/fixed clauses pre .. result)<br>
> (for clauses<br>
> pre ...<br>
> (printf "~v\n" (let () result))))<br>
><br>
> Carl Eastlund<br>
><br>
><br>
> On Fri, Sep 6, 2013 at 12:25 PM, Matthew Flatt <<a href="mailto:mflatt@cs.utah.edu">mflatt@cs.utah.edu</a>> wrote:<br>
><br>
> ><br>
> > #lang racket/base<br>
> > (require (for-syntax racket/base<br>
> > syntax/parse<br>
> > syntax/for-body))<br>
> ><br>
> > (define-syntax (for/print/good stx)<br>
> > (syntax-parse stx<br>
> > [(_ clauses . body)<br>
> > (with-syntax ([([pre ...] [post ...]) (split-for-body stx #'body)])<br>
> > (syntax<br>
> > (for clauses<br>
> > pre ...<br>
> > (printf "~v\n" (let () post ...)))))]))<br>
> ><br>
> > (define-syntax-rule (for/print/bad clauses pre ... result)<br>
> > (for clauses<br>
> > pre ...<br>
> > (printf "~v\n" result)))<br>
> ><br>
> > ;; Try changing to for/print/bad:<br>
> > (for/print/good ([i 1])<br>
> > (define (fish? v) (or (red? v) (blue? v)))<br>
> > (begin<br>
> > (define (red? v) (eq? v 'red))<br>
> > (define (blue? v) (eq? v 'blue))<br>
> > (fish? i)))<br>
> ><br>
> ><br>
> > At Fri, 6 Sep 2013 12:17:56 -0400, Carl Eastlund wrote:<br>
> > > Right, that's the issue with needing the (let () result) in my<br>
> > > define-syntax-rule version. I still didn't need split-for-body, which<br>
> > > doesn't guarantee there are no definitions in the post ... part. All it<br>
> > > guarantees to eliminate are #:final and #:break.<br>
> > ><br>
> > > Carl Eastlund<br>
> > ><br>
> > ><br>
> > > On Fri, Sep 6, 2013 at 12:09 PM, Matthew Flatt <<a href="mailto:mflatt@cs.utah.edu">mflatt@cs.utah.edu</a>><br>
> > wrote:<br>
> > ><br>
> > > > The issue is `begin` splicing. The `result` form could be a `begin`<br>
> > > > form that contains definitions that are referenced by a preceding<br>
> > > > forms.<br>
> > > ><br>
> > > > For example, given<br>
> > > ><br>
> > > > (define (fish? v) (or (red? v) (blue? v)))<br>
> > > > (begin<br>
> > > > (define (red? v) ....)<br>
> > > > (define (blue? v) ....)<br>
> > > > 5)<br>
> > > ><br>
> > > > With `begin` splicing, that turns into<br>
> > > ><br>
> > > > (define (fish? v) (or (red? v) (blue? v)))<br>
> > > > (define (red? v) ....)<br>
> > > > (define (blue? v) ....)<br>
> > > > 5<br>
> > > ><br>
> > > > which is different than<br>
> > > ><br>
> > > > (define (fish? v) (or (red? v) (blue? v)))<br>
> > > > (let ()<br>
> > > > (define (red? v) ....)<br>
> > > > (define (blue? v) ....)<br>
> > > > 5)<br>
> > > ><br>
> > > > At Fri, 6 Sep 2013 11:15:50 -0400, Carl Eastlund wrote:<br>
> > > > > Is this function ever particularly necessary? Its intended use<br>
> > seems to<br>
> > > > be<br>
> > > > > like so:<br>
> > > > ><br>
> > > > > (define-syntax (for/print stx)<br>
> > > > > (syntax-parse stx<br>
> > > > > [(_ clauses . body)<br>
> > > > > (with-syntax ([([pre ...] [post ...]) (split-for-body #'body)])<br>
> > > > > (syntax<br>
> > > > > (for clauses<br>
> > > > > pre ...<br>
> > > > > (printf "~v/n" (let () post ...)))))]))<br>
> > > > ><br>
> > > > > That way any #:break or #:final from the body ends up in pre ...,<br>
> > where<br>
> > > > the<br>
> > > > > enclosing for loop will interpret them, and post ... will only<br>
> > include<br>
> > > > > normal definitions and expressions.<br>
> > > > ><br>
> > > > > But it seems to me there's a much easier way that should always work:<br>
> > > > ><br>
> > > > > (define-syntax-rule (for/print clauses pre ... result)<br>
> > > > > (for clauses<br>
> > > > > pre ...<br>
> > > > > (printf "~v\n" result)))<br>
> > > > ><br>
> > > > > This not only puts all #:break and #:final clauses in pre ..., it<br>
> > should<br>
> > > > > guarantee result is an expression. Perhaps one should still write<br>
> > (let<br>
> > > > ()<br>
> > > > > result) in case result is (begin defn expr), but that's still simpler<br>
> > > > than<br>
> > > > > using split-for-body.<br>
> > > > ><br>
> > > > > My question is -- have I overlooked some clever subtlety here that<br>
> > makes<br>
> > > > > split-for-body necessary, or is it usually easier to just decompose<br>
> > pre<br>
> > > > ...<br>
> > > > > result rather than bothering with split-for-body?<br>
> > > > ><br>
> > > > > Carl Eastlund<br>
> > > > > _________________________<br>
> > > > > Racket Developers list:<br>
> > > > > <a href="http://lists.racket-lang.org/dev" target="_blank">http://lists.racket-lang.org/dev</a><br>
> > > ><br>
> > > ><br>
> ><br>
> ><br>
<br>
</div></div></blockquote></div><br></div>