But I think it’s important that it doesn’t use gensym or something like that, it uses syntax-marks, which means you can break these lexical scoping rules if you want/need to by using either syntax-local-introduce or datum->syntax:
#lang racket (require syntax/parse/define) (define-simple-macro (with-tables stem body ...) #:with table-author-id (syntax-local-introduce #'table-author) (let([table-publication (string-append stem "_publication")] [table-author-id (string-append stem "_author")] [table-bridge-publication-author (string-append stem "_bridge_publication_author")] [table-unique-counters (string-append stem "_unique_counters")] ) body ... )) (with-tables "x" table-author) ;”x_author" On Jan 15, 2015, at 9:23 PM, Alexander McLin <alex.mc...@gmail.com> wrote: > Warning I am still a Racket intermediate user but I've been studying > syntactic extensions a lot the past several months. > > The problem here is macros in Racket have lexical scope just like procedures, > they are hygienic macros. The identifiers you introduced in the with-tables > macro only exist or refer to other bindings in the same lexical scope as > where you originally wrote the macro. > > When you invoke the macro and pass in table-author, even though it is spelled > the same as the identifier you wrote in the macro definition, they are not > the same. When the macro expands, hygiene is implemented by renaming all > identifiers in the macro to unique non-clashing symbols that don't conflict > with others existing in the scope the macro is expanding in. > > The table-author identifier in the macro in the let form is renamed to > something different like g6271 or something along those lines. > > Furthermore, you need to be careful about what you mean by evaluation. In the > presence of macros, you have the concept of syntax phase(or compile-time or > expand-time) evaluation versus run-time evaluation. When the macro is > expanding, it does it thing, processing the original syntax into the new > piece of syntax that replaces what was there previously such as (with-tables > "x" table-author) which is then finally evaluated during run-time. > > (with-tables "x" table-author) will expand into something looking similar to > the following, just to give you an idea of what macro expansion looks like: > > (let ((g6191 (string-append "x" "_publication")) > (g6271 (string-append "x" "_author")) > (g6369 (string-append "x" "_bridge_publication_author")) > (g6445 (string-append "x" "_unique_counters"))) > table-author) > > Note that the original table-author identifier has been replaced by a > different identifier that still has the same binding you originally defined. > > The table-author identifier you passed to the macro gets inserted in the body > position and then the expanded code is evaluated at run-time and of course > gives you a run-time error since table-author does not refer to anything and > thus when it's evaluated, it is recognized as an undefined identifier. > > (with-tables "x" "hello") works because what you get in return is: > > (let ((g6191 (string-append "x" "_publication")) > (g6271 (string-append "x" "_author")) > (g6369 (string-append "x" "_bridge_publication_author")) > (g6445 (string-append "x" "_unique_counters"))) > "hello") > > "hello" is just a self-evaluating string giving you back "hello" from within > the let form. > > On Thu, Jan 15, 2015 at 12:12 AM, Thomas Lynch > <thomas.ly...@reasoningtechnology.com> wrote: > I have a simple syntax rule: > > Welcome to Racket v5.2.1. > racket@> (define-syntax-rule (with-tables stem body ...) > (let( > [table-publication (string-append stem "_publication")] > [table-author (string-append stem "_author")] > [table-bridge-publication-author (string-append stem > "_bridge_publication_author")] > [table-unique-counters (string-append stem "_unique_counters")] > ) > body ... > )) > > Which works fine when I don't reference the environment defined by the let: > > racket@> > racket@> (with-tables "x" "hello") > "hello" > > > However when I pass it an identifier corresponding to one of the variables > defined in the let: > > racket@> (with-tables "x" table-author) > reference to undefined identifier: table-author > stdin::1167: table-author > > The identifier passed in doesn't seem to be part of the local let context, > but carried in a different context, or perhaps it was evaluated as an > operand. I didn't expect either of those. Can someone point me at a > description of the expected behavior, or give me a tip here on what is > happening and why. > > ... in Wolfram language there is a 'Hold' operator for situations like this. > Apparently inside the macro we have to do some evaluation to handle the work > of the macro, is that why the operand is evaluated? > > Thanks in advance for explaining the evaluation/context model here. > > Thomas > > _________________________ > Racket Developers list: > http://lists.racket-lang.org/dev > > > _________________________ > Racket Developers list: > http://lists.racket-lang.org/dev
_________________________ Racket Developers list: http://lists.racket-lang.org/dev