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

From: Stephen Chang (stchang at ccs.neu.edu)
Date: Sun Sep 8 15:58:16 EDT 2013

>> So is the reason why #:when and #:unless can't be used the same way
>> because there already exist when and unless forms?
>
> Are you looking for an equivalent of C's "continue" statement?  I could
> imagine clauses for skipping to the next iteration using the keyword
> #:continue or #:next, though I have no idea if the existing loop
> architecture would easily accommodate them.  I don't think calling them
> #:when or #:unless makes sense outside the for clauses.

Hmm, I take back my previous question, which didn't make sense
(because it may result in unwanted voids). Now I'm thinking #:when and
#:unless *should* be allowed in the body, for the exact reasons why
#:final and #:break are allowed. But presumably there is a reason they
were left out?

It would be similar to C's continue, but the names should probably be
the same, since they do the same thing as clause-based #:when/unless?

Yes, I think the current architecture would support this change easily
since it's accumulator-based. If a #:when/unless condition is true,
you just call the loop with the old accumulators. I can put it in if
there is agreement.


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

Posted on the dev mailing list.