[racket-dev] internal-definition parsing

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Wed Oct 13 10:08:45 EDT 2010

In the case I have, though, I want the sequence to be empty.  The
problem is that these bodies -- (let () ...), (parameterize () ...),
etc. -- are used for a lot of different things.  A macro may splice in
a sequence that is intended to represent definitions to bind in a
scope, expressions to evaluate for effect, expressions to evaluate in
order and return the last, mixed definitions and expressions, or
perhaps some other odd interpretation of the body sequence.

I have some RackUnit test cases that are currently empty as I have no
checks to put in them.  They're just placeholders.  Under the
planet-based SchemeUnit, this works fine.  Under RackUnit, it expands
into (parameterize ([stuff ...])), because there are no body
expressions.  This happens about 2-3 macros down from where I write
it.  We could start adding "blame" and possibly making various macros
add (block e ...), but really, why not just make it work?  It seems a
lot easier, and all it means is that you get in trouble if you forget
to write the body of your function.  That's not really that surprising
an error.  The (define (f) ... (define (g) ...)) bug Matthew
originally cited is fairly easy to debug, too.  Running into a problem
with nested macros imported from someone else's libraries is something
I'd much rather make easy.

Carl Eastlund

On Wed, Oct 13, 2010 at 10:02 AM, Matthias Felleisen
<matthias at ccs.neu.edu> wrote:
> In a sense you just want to change the 'fault blame' designation when
>  e/d ...
> moves from macro foo to macro bar so that bar isn't blamed. It is then
> foo's job to ensure that the sequence isn't empty and foo is blamed when
> things go wrong.
> I suspect this can be solved in syntax-parse, too.
> -- Matthias
> On Oct 13, 2010, at 8:34 AM, Matthew Flatt wrote:
>> At Wed, 13 Oct 2010 08:23:09 -0400, Carl Eastlund wrote:
>>> On Wed, Jul 7, 2010 at 12:23 PM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
>>>> Should an expression be required at the end? A `module', `unit', or
>>>> `class' body can consist of just definitions. Similarly, if an
>>>> internal-definition context ends with a definition, we could define the
>>>> result to be `(void)', which is what the `block' form does.
>>>> I think it's better to require an expression at the end, partly on the
>>>> grounds that the internal-definition block is supposed to return a
>>>> value (unlike the body of `module', etc.) and partly to avoid making
>>>> forms like
>>>>  (define (f x)
>>>>   x
>>>>  (define (g y)
>>>>   y))
>>>> legal when they are almost certainly mistakes.
>>> Macros constructing sequences of def-or-expr for implicit begin (as
>>> found in let, lambda, parameterize, etc.) won't always know if the
>>> sequence is empty or non-empty, and whether it is terminated by an
>>> expression or definition.  If a begin-like sequence ends with a
>>> definition, currently a macro must add an expression such as (void) to
>>> follow it.  If it ends with an expression, the macro must *not* add
>>> such an expression, because that changes the return value.  It would
>>> be far more convenient if primitive forms worked with any sequence of
>>> def-or-expr so that each wrapper macro did not have to implement its
>>> own local-expand loop to figure out how the sequence ends, and as
>>> always it is much nicer to write macros when sequences can be
>>> zero-length.
>> How about the option of using `block' in the macro implementation,
>> instead of allowing forms like `(let ())', `(define (h))', the `f' and
>> `g' example above?

Posted on the dev mailing list.