[plt-scheme] Confusion about lexical scoping, modules, and hygenic macros

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Aug 17 08:55:28 EDT 2005

At Tue, 16 Aug 2005 22:22:06 -0700 (PDT), Danny Yoo wrote:
>   (define-syntax arrow
>     (syntax-rules (->)
>       [(arrow -> x)
                ^^
As you expect, this means "match an identifier same binding as `->'
here", which is to say, an identifier with no binding whose symbolic
name is `->'.

> However, the following gives a very surprising result:
> 
> ;;;;;;
> > (module m3 mzscheme
>   (require (lib "contract.ss"))
>   (require m1)
>   (display (arrow -> this-is-from-m3))
>   (newline))
> repl-2:4:11: arrow: bad syntax in: (arrow -> this-is-from-m3)
> ;;;;;;
>
> I think I understand what's causing this.  Somehow, during macro
> expansion, the macro system's convinced that '->' is lexically bound,

Yes. Within `m3', `->' is bound to a contract constructor by the import
of "contract.ss". So the `->' in the use of `arrow' does not match the
`->' in the definition.

> From the toplevel:
> 
> ;;;;;;;;
> > (define -> 'blah)
> > (require m1)
> > (arrow -> 'ok-please-break)
> ((quote ok-please-break) is arrowed!)

The top level is hopeless. Since top-level identifiers might be
referenced before they are defined, there's no distinction at the top
level between "not bound" and "bound by a top-level variable".

Note that

 > (define-syntax -> ...)
 > (require m1)
 > (arrow -> 'this-will-fail)

will produce a syntax error for the use of `arrow'. There's a
difference between "not bound" and "bound to top-level syntax" (and you
can't refer to a syntax binding before its definition at the top level).

Matthew



Posted on the users mailing list.