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

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Fri Sep 6 12:25:14 EDT 2013

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

Posted on the dev mailing list.