[plt-scheme] let-syntax bug

From: Bradd W. Szonye (bradd+plt at szonye.com)
Date: Thu Apr 8 13:37:31 EDT 2004

Bradd W. Szonye wrote:
>>     (let-syntax ((foo ...))
>>       (define-syntax bar (syntax-rules () ((bar) 'hello))))
>> The syntactic binding of BAR is clearly nested inside FOO's region.
>> Migrating BAR outside of the LET-SYNTAX region would clearly break
>> syntactic scoping, which is IMO a very, very bad idea.

Andre van Tonder wrote:
> Except that "internal definitions" are already allowed in transformer
> templates.   

True, but (DEFINE-SYNTAX ...) is not an internal definition. While some
Schemes permit internal syntax definitions as an extension, R5RS does
not. However, for the sake of argument, let's assume that it does.

> In regular Scheme, the following
>   (define f 
>     (lambda () expr)
>   (f)            
> gives the same answer as 
>   (letrec ((f (lambda () expr)))
>     (f))         


> In analogy, my expectation would therefore be that 
>   (define-syntax f
>    (syntax-rules ()
>      ((f) expr))))
>   (f)
> should give the same as 
>   (letrec-syntax ((f (syntax-rules () expr)))
>     (f))

Again, this analogy only makes sense if you assume the existence of
first-class syntax values, which do not exist in Scheme (for good reason
-- see Bawden's article on first-class macros for details). However,
let's also assume that these exist.

> However, this is not the case when expr is an internal define-syntax.  

I wouldn't expect it to, even if you assume the existence of internal
define-syntax and first-class syntax values. Here's the syntax version:

    (letrec-syntax ((f (syntax-rules ()
                         ((_) (define-syntax g () ((_) ...))))))

Now convert that back to its let/define equivalent:

    (letrec ((f (lambda () (define (g) ...))))

If your analogy is correct, this should return (define (g) ...), which
doesn't make sense. This analogue isn't even valid Scheme: The LAMBDA
syntax is incorrect, because there is no <sequence> after the

    <lambda expression> --> (lambda <formals> <body>)
    <body> --> <definition>*    <sequence>
           ==> (define (g) ...) ???

That makes sense; you can only return expressions, not definitions.
Then again, the LETREC-SYNTAX version isn't valid Scheme either; it
expands to

    (letrec-syntax ((f ...))
      (define-syntax g ...))

which cannot further expand to any valid expression or syntax
expression. I see only four "intuitive" ways to read it:

1. It's an error, because define-syntax can only appear at top-level.
2. It's an error, because there's no expression after the internal
3. It's a no-op.
4. It breaks the scope of F to define G at top-level.

The analogy with LETREC and internal DEFINE suggests #1 or #2, depending
on whether the implementation permits internal DEFINE-SYNTAX.

In short, I think your analogy leads to an attempt to "return" an
internal definition somehow, which is currently an error both for normal
expressions and for syntax. Furthermore, it's an error for a good
reason: permitting it would break scoping.
Bradd W. Szonye

Posted on the users mailing list.