[plt-scheme] Re: Why compare identifiers using phase zero?
At 01 May 2004 15:20:32 -0500, Jim Blandy wrote:
> In your "Composable and compilable macros" paper, the definition of
> "resolve" in figure 3 decides when a 'subst' applies to the identifier
> in hand by comparing the marks and the resolved identifiers, as in the
> usual Dybvig / Hieb fashion.
>
> For comparing the resolved identifiers, however, it recurs on resolve
> in phase zero, not phase p. The effect is to only recognize 'reqd'
> annotations for local definitions and 'require' imports. I'm not sure
> I understand why this is right.
The choice of phase is arbitrary --- 99 or `p' would have worked as
well as 0. (I used 0 instead of `p' to help clarify that the choice is
arbitrary. Maybe 99 would have been better. :)
The phase doesn't matter because there is no binding form that shadows
a specific phase. In particular, `subst' corresponds to bindings that
shadow in all phases.
If a language made lexical variables bind only in a specific phase, or
if `require' and `require-syntax' could be used in internal-definition
positions, then I think that the recursive resolution for `subst' would
need to use phase `p'.
> A separate question, or maybe related:
>
> If I try to compile:
>
> (let-syntax (a (lambda (sa)
> (let-syntax (b (lambda (sb)
> ... body of 'b' macro expander ...))
> ... body of 'a' macro expander ...)))
> ... top-level expression ...)
>
> the expander for 'b' will be evaluated in phase 2. What bindings are
> in scope for that expander?
None.
> There's no way to get 'reqd' annotations with a phase of 2: in the
> description of 'Module Compilation', it only discusses introducing
> 'reqd's with phases 0 or 1.
They can only appear as a result of phase-shifting a module for
`require-for-syntax'.
This means that a literal `let-syntax' in a compile-time position is
never useful. However, a macro might use a macro that was imported with
`require-for-syntax', and the imported macro might usefully expand to
`let-syntax'.
Here's an example:
(define n mzscheme
(require-for-syntax p)
(define-syntax n-macro ... #'(let-syntax ([... ...#'p...]) ...))
...)
(define m mzscheme
(require-for-syntax n)
(define-syntax m-macro ... (n-macro ...) ...)
...)
Expanding `m' leads to a phase-2 binding of `p' in the implementaion of
`m-macro'. (The `let-syntax' and the `p' go away in the complete
expansion, though.)
FWIW, this happens every time you use `syntax-case' in a macro
implementation. The `syntax-case' form expands to a `let-syntax' that
refers to a phase-2 struct constructor.
Matthew