[plt-scheme] Confusion about lexical scoping, modules, and hygenic macros
On Wed, 17 Aug 2005, Matthew Flatt wrote:
> > ;;;;;;
> > > (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.
Hi Matthew,
Thanks for the explanation; ok, so I was definitely confused. I just have
to expand my understanding of "lexical binding" to treat modules in that
special way.
I always thought that lexical binding only meant then the code was
physically nested --- as with let --- but I see now that anything defined
bound at module-level should also be considered lexically bound within
that module. (I think it's very obvious I'm still trying to graduate from
my "Intro to CS using Scheme" days. *grin*)
That makes sense, though the implications of it troubles me a bit; if I
understand it properly, it implies that the usage of syntax to represent
keywords can be a bit fragile unless we take precautions.
[reading more through the reference manual]
Ah, ok, I see! So there is an extended version of syntax-case called
syntax-case* which accepts an arbitrary comparator for the pattern
literals. So something like:
;;;;;;
(module m1 mzscheme
(provide (all-defined))
(define-syntax (arrow stx)
(define (symbolic-identifier=? x y)
(eqv? (syntax-object->datum x)
(syntax-object->datum y)))
(syntax-case* stx (->) symbolic-identifier=?
[(arrow -> x)
(syntax/loc stx
(list (quote x) 'arrowed!))])))
;;;;;;
is a little uglier, but it allows me to define a reserved keyword in the
way I was expecting. Let me check:
;;;;;;
> (module m3 mzscheme
(require (lib "contract.ss"))
(require m1)
(display (arrow -> this-is-from-m3))
(newline))
> (require m3)
(this-is-from-m3 arrowed!)
;;;;;;
Great! That works much better.
Thanks again for your help!