[racket-dev] some surprising behavior with syntax-parameterize and lexical info

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Fri Apr 6 18:38:02 EDT 2012

On 04/06/2012 12:47 PM, Danny Yoo wrote:
>>> I suspect that I should be using quote-syntax at this specific point,
>>> but I am not completely sure.
>> Right. Try replacing ??? with (quote-syntax #,a-placeholder).
> I have to admit that I'm still confused.  Here's my example:
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> #lang racket
> (require racket/stxparam racket/splicing)
> (define-syntax-parameter current-def #f)
> (define-syntax (def stx)
>   (syntax-case stx ()
>     [(_ (name args ...) body ...)
>      (with-syntax ([function-stx stx])
>        (syntax/loc stx
>          (define (name args ...)
>            (splicing-syntax-parameterize ([current-def
>                                            (quote-syntax
> function-stx)])
>              body ...))))]))

You moved the 'splicing-syntax-parameterize' back inside the scope of 
'args'. That's why it doesn't work. Here's the correct version:

(define-syntax (def stx)
  (syntax-case stx ()
    [(_ (name args ...) body ...)
     (with-syntax ([function-stx stx])
       (syntax/loc stx
             ([current-def (quote-syntax function-stx)])
           (define (name args ...)
             body ...))))]))

>  From what I understand of quote-syntax, it should create a syntax
> object that preserves the lexical information in function-stx.
> function-stx should be a syntax object whose lexical information does
> not include the function argument's variables.  Yet, when I run this,
> the program prints 4, rather than 84 as I expected.

At the time 'def' is expanded, the lexical context of 'function-stx' 
does not include the bindings of 'args'. But then the macro produces an 
expression with that term inside a 'quote-syntax' form that is inside 
the scope of the 'args'. So by the time the expander gets to the 
'quote-syntax' form, the lexical context of the original term has been 
enriched with the 'args' bindings.

In other words, the appearance of 'quote-syntax' in a macro template 
doesn't magically freeze the lexical context of its argument then and 
there. What matters is the lexical context when the expander reaches the 
'quote-syntax' expression itself.

That's why (quote-syntax function-stx) needs to go outside the binding 
of the 'args'.

(There are tricks (eg, 3D syntax or syntax properties) that can hide the 
syntax from the expander so it doesn't get the 'args' wraps, but they're 
fragile. And hacky. Don't use them.)


Posted on the dev mailing list.