[plt-scheme] Re: Why compare identifiers using phase zero?

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sun May 2 11:24:00 EDT 2004

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



Posted on the users mailing list.