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

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Sep 6 14:46:31 EDT 2013

On Fri, Sep 6, 2013 at 2:43 PM, Stephen Chang <stchang at ccs.neu.edu> wrote:

> On Fri, Sep 6, 2013 at 2:36 PM, Carl Eastlund <cce at ccs.neu.edu> wrote:
> > They have to be separate internal definition contexts in order for
> #:break
> > and #:final to be able to stop execution before the definitions
> themselves
> > get run.
>
> Hmm, ok. I guess my question was why does one need #:final and #:break
> in the body like that?
>

It's useful when the condition for loop termination and the value of the
loop body both depend on some derived computation from the sequence
elements:

(for/list ([x (in-stream S)])
  (define y (f x))
  #:break (g? y)
  (h y))

> Carl Eastlund
> >
> >
> > On Fri, Sep 6, 2013 at 2:31 PM, Stephen Chang <stchang at 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 <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
> >> >
> >>
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20130906/5518ef36/attachment-0001.html>

Posted on the dev mailing list.