[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: #%app problems with nested macro
Quoting "Greg Pettyjohn":
> But if I nest the second macro with the first --- like this:
>
> (define-syntax my-let
> (lambda (x)
>
> (define-syntax with-values
> (lambda (x)
> (syntax-case x ()
> [(_ P C) #'(call-with-values (lambda () P) C)])))
>
> (syntax-case x ()
> [(_ () body) #'((lambda () body))]
> [(_ ((var* val*) ...) body)
> #'((lambda (var* ...) body) val* ...)])))
>
> I will get the following error:
>
> compile: bad syntax; function application is not allowed, because no #%app
> syntax transformer is bound in: (lambda (x) (syntax-case x () ((_ p c)
> (syntax (call-with-values (lambda () p) c)))))
The right-hand side (RHS) of a `define-syntax' has a different
top-level environment than the `define-syntax' expression itself,
because the RHS is in a dififferent phase.
The initial namespace imports all of the MzScheme forms into the
run-time ("phase 0") top-level environment and into the compile-time
("phase 1") top-level environment. Thus, `cons' is available in both of
the following places:
(define-syntax x ... (cons 1 2) ...)
(cons 1 2)
But, in priciple, they are different `cons'es --- one for compilation
today on my machine, and another for execution next week on someone
else's machine.
If you put a `define-syntax' in the RHS of a `define-syntax', then the
RHS of the inner `define-syntax' lives at compiler-compile time ---
"phase 2". MzScheme doesn't provide a mechaism for importing into
phases deeper than 1, so the inner RHS has no initial bindings. (In
thoery, MzScheme could support phase-N imports. We'll look at this
possibility in v201.)
The module system lets you shift phases through `require-for-syntax'.
But such a shift is needed only when you're defining syntax used in
phase 1 to implement the transformation of phase 0 code.
In this case, my guess is that references to `with-values' will appear
in the expansion of `my-let' (or `my-let-values'?), as opposed to
appearing in code that generates the expansion of `my-let'. If my guess
is correct, then you'll have to implement `my-let' within a module, and
put `with-values' in the same module (unexported).
> I tried writing this macro at top level:
>
> (define-syntax #%app
> (lambda (x)
> (syntax-case x ()
> [(_ rator rands ...) #'(apply rator rands ...)])))
>
> When I click execute, it goes forever (actually, I didn't wait that long).
In this case, there's a hidden `#%app' before apply', which is why it
loops.
> If I put the #%app macro at the same scope as with values:
>
> (define-syntax my-let
> (lambda (x)
>
> (define-syntax #%app
> (lambda (x)
> (syntax-case x ()
> [(_ rator rands ...) #'(apply rator rands ...)])))
>
> (define-syntax with-values
> (lambda (x)
> (syntax-case x ()
> [(_ P C) #'(call-with-values (lambda () P) C)])))
>
> (syntax-case x ()
> [(_ () body) #'((lambda () body))]
> [(_ ((var* val*) ...) body)
> #'((lambda (var* ...) body) val* ...)])))
>
> I get:
>
> compile: identifier used out of context in: #%app
Absolutely confusing.
It turns out that nothing past the `#%app' definition matters. And if
we can simplify the `#%app' as follows, we still get the out-of-context
error:
(define-syntax my-let
(lambda (x)
(define-syntax #%app (z))
10))
There's a hidden `#%app' before the `z'. It's used in a phase 2
position, but captured by the internal definition for `#%app'. The
interally defined `#%app', meanwhile, is for code at phase 1. Using a
phase-N identifier in a phase-M position is an out-of-context error if
N != M.
[Note: different phases have different top-level environments, but
non-top-level bindings capture across phases. So that's how an
out-of-context error is possible.]
> +-----------------------------------------------------
> Finally I tried this:
>
> (define-syntax my-let
> (lambda (x)
>
> (define-syntax with-values
> (lambda (x)
> (define-syntax #%app
> (lambda (x)
> (syntax-case x ()
> [(_ rator rands ...) #'(apply rator rands ...)])))
> (syntax-case x ()
> [(_ P C) #'(call-with-values (lambda () P) C)])))
>
> (syntax-case x ()
> [(_ () body) #'((lambda () body))]
> [(_ ((var* val*) ...) body)
> #'((lambda (var* ...) body) val* ...)])))
>
> And I get the seemingly contradictory error message:
>
> compile: bad syntax; function application is not allowed, because no #%app
> syntax transformer is bound in: (lambda (x) (define-syntax #%app (lambda (x)
> (syntax-case x () ((_ rator rands ...) (syntax (apply rator rands ...))))))
> (syntax-case x () ((_ p c) (syntax (call-with-values (lambda () p) c)))))
Similar to above, except that this time there is no internal definition
of `#%app' to capture the hidden `#%app' in front of `lambda'. Also,
there's no top-level definition of `#%app' in phase 2. So the phase-2
`#%app' is free.
Matthew