[racket-dev] split-for-body from syntax/for-body

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Sep 6 12:58:29 EDT 2013

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 bodyevaluations, 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
> > > > >
> > > > >
> > >
> > >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20130906/4c1bc0d8/attachment-0001.html>

Posted on the dev mailing list.