[racket-dev] question, issue(?) with the scope of identifiers passed into define-syntax-rule

From: Alexander McLin (alex.mclin at gmail.com)
Date: Thu Jan 15 21:23:21 EST 2015

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.lynch at reasoningtechnology.com> wrote:

> I have a simple syntax rule:
>
>   Welcome to Racket v5.2.1.
>   [email protected]> (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:
>
>
>   [email protected]>
>   [email protected]> (with-tables "x" "hello")
>
>   "hello"
>
>
> However when I pass it an identifier corresponding to one of the variables
> defined in the let:
>
>   [email protected]> (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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20150115/decfa1c3/attachment.html>

Posted on the dev mailing list.