[plt-scheme] macro question

From: Jos Koot (jos.koot at telefonica.net)
Date: Sat Jun 7 05:56:28 EDT 2008

'es' introduced in the macro is not identified with the local variable 'es' 
of the environment from which the macro is called. This is hygienic. The 
hygienic behaviour avoids unintentional identifications. Besides there might 
also hang around a global variable of the same name, in which case your 
macro would identify 'es' with the global variable, not the local one. Below 
two solutions, the first one non hygienic, the second one hygienic by 
requiring the variable to be mentioned in the macro call. In general 
hygienic solutions are to be preferred, I think.

(define-syntax (get-stack-vals stx)
   (syntax-case stx ()
   ((_ n (env first rest) expr ...)
    #`(let*-values (((env stk) (es-values #,(datum->syntax stx 'es)))
                    ((first rest) (take n stk)))
        expr ...))))

(define-syntax get-stack-vals
   (syntax-rules ()
   ((_ n (env first rest) es expr ...)
 ;                              ^^^
    (let*-values (((env stk) (es-values es))
                    ((first rest) (take n stk)))
        expr ...))))

----- Original Message ----- 
From: "Michael Vanier" <mvanier at cs.caltech.edu>
To: "mzscheme Mailing List" <plt-scheme at list.cs.brown.edu>
Sent: Saturday, June 07, 2008 11:17 AM
Subject: [plt-scheme] macro question

> I've run into a problem with a macro I don't know how to solve.  Here's 
> the macro:
> (define-syntax get-stack-vals
>   (syntax-rules ()
>     ((_ n (env first rest) expr ...)
>      (let*-values (((env stk) (es-values es))
>                    ((first rest) (take n stk)))
>        expr ...))))
> Here's a use:
> (define (do-def es)
>   (get-stack-vals 2 (env first rest)
>      (let ((sym (cadr first))
>            (val (car first)))
>        (if (symbol? sym)
>            (let ((env2 (env-add env sym val)))
>              (make-es env2 rest))
>            (error "cannot define non-symbol: " sym)))))
> which should expand to:
> (define (do-def es)
>   (let*-values (((env stk) (es-values es))
>                 ((first rest) (take 2 stk)))
>     (let ((sym (cadr first))
>           (val (car first)))
>       (if (symbol? sym)
>           (let ((env2 (env-add env sym val)))
>             (make-es env2 rest))
>           (error "cannot define non-symbol: " sym)))))
> and apparently does, at least according to the macro stepper.  However, 
> when I call do-def I get an error message: "reference to undefined 
> identifier: es".  This seems odd, because es is in scope at the macro 
> expansion location.  Is the es in the get-stack-vals macro bound in the 
> lexical scope of that macro?  All the other external identifiers in the 
> macro are bound at the top-level, so it works either way for them.  If 
> this is the case, how do I get es to be bound the way I want it to be?  I 
> realize that I'm trying to do something a bit naughty since I'm assuming a 
> binding for es will exist at all macro expansion locations; alternative 
> suggestions are welcome (other than "don't give up your day job").
> I'm a macro newbie, so please be gentle ;-)  PLT Scheme's macro system is 
> an intricate and beautiful thing that I'm just beginning to wrap my head 
> around.
> Mike
> _________________________________________________
>  For list-related administrative tasks:
>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme 

Posted on the users mailing list.