[racket-dev] split-for-body from syntax/for-body
> "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 <cce at 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 <mflatt at 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 <mflatt at 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 <mflatt at 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
>