[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Introductory material on hygienic macros in dr scheme

Quoting =?iso-8859-1?Q?Breannd=E1n =D3 Nuall=E1in?=:
>   >> > (let-syntax ((foo (syntax-rules () ((_ x) (bar x)))))
>   >>     (define x 33)) 
> [...]
>     Matthew> In the "internal definitions" section:
>     Matthew>  Definitions may occur at the beginning of a <body> (that
>     Matthew> is, the body of a lambda, let, let*, letrec, let-syntax,
>     Matthew> or letrec-syntax expression or that of a definition of an
>     Matthew> appropriate form). Such definitions are known as internal
>     Matthew> definitions as opposed to the top level definitions
>     Matthew> described above.
>  [...]
> But surely the above `define' should not be treated as internal? 

Are we reading the above paragraph from R5RS differently, or are you
suggesting that this part of R5RS is wrong? (I don't consider R5RS
sacred, of course.)

> At most it should be treated as a `define' inside a top-level `begin' as
> given in Section 5.1 of R5RS:
>   "At the top level of a program (begin <form1> ...) is equivalent to
>   the sequence of expressions, definitions, and syntax definitions that
>   form the body of the begin."

I don't see any top-level `begin's in the above program fragment, so
I'm not really sure what you're getting at.

> This seems to be what mzscheme is trying to do: wrap it in an implicit
> `begin' only then to grumble that the `define' appears in a `begin'
> with no further expressions.

In MzScheme, the body of `let-syntax' is a position for internal
definitions. So, yes, it wraps the `let-syntax' body in an implicit

>     Matthew> The Chez model seems to it interact confusingly
>     Matthew> (wrongly?) with internal definitions. Here's the simplest
>     Matthew> example that I could manage:
>     Matthew> (let-syntax ([ack
>     Matthew>               (syntax-rules ()
>     Matthew>                 [(_) 'outer-ack])])
>     Matthew>   (letrec-syntax ([foo
>     Matthew>                    (syntax-rules ()
>     Matthew>                      ((_ x) (define (x) (bar))))]
>     Matthew>                   [bar
>     Matthew>                    (syntax-rules ()
>     Matthew>                      ((_) (ack)))]) ;; <<<<<
>     Matthew>     (foo x))
>     Matthew>   (define (ack) 'inner-ack)
>     Matthew>   (x))
>     Matthew> Which `ack' is the one marked by "<<<<<" ? If the
>     Matthew> `letrec-syntax' expression produces a definition, then we
>     Matthew> have a two-definition internal sequence, and `(define
>     Matthew> (ack) 5)' should bind the marked `ack'. [...]
>     Matthew> However, Chez produces 'outer-ack for the first
>     Matthew> expression [...]
> Is this really right?  

No... `ack' wasn't an internal definition. I'm so used to `let-syntax'
introducing internal definitions that my example wasn't what I meant.
(I ended up tripping over top-level order problems, instead.)

Here's what I meant:

  (let-syntax ([ack
		(syntax-rules ()
		  [(_) 'outer-ack])])
    (let ()
      (letrec-syntax ([foo
		       (syntax-rules ()
			 ((_ x) (define (x) (bar))))]
		       (syntax-rules ()
			 ((_) (ack)))]) ;; <<<<<
	(foo x))
      (define (ack) 'inner-ack)

which produces 'inner-ack in Chez (correctly).

The difference between Chez and MzScheme is that MzScheme reveals the
partial-expansion mechanism to the programmer, so macros like `class',
`unit', and `local' are possible to implement (with meaningful error
messages). Chez keeps the partial-expansion mechanism private, so it
can avoid any problem that I can imagine. But I don't think that Chez
can support a `local' macro where, say,

 (let ([w (lambda (y) y) ])
   (local ( (define x 10)
            (w) ) ;; not a def

is syntactically rejected (because the macro can't tell whether `w'
expands to a definition).

If we can find a way to eliminate partial expansion, then MzScheme
could certainly act like Chez. That's an area for future work, though.