4

The R5RS spec states that as part of the requirements for a macro defined using syntax-rules:

If a macro transformer inserts a free reference to an identifier, the reference refers to the binding that was visible where the transformer was specified, regardless of any local bindings that may surround the use of the macro.

I am trying to understand how this works in practice. So for example, if I have the following code:

(define var 'original)

(define-syntax test-var
 (syntax-rules (var)
   ((_ var)
    var)
   ((_ pattern-var)
    'no-match)))

I would expect the following, if executed immediately after, to evaluate to original, which it does:

(test-var var)

And I would expect this one to be no-match since the var introduced into scope prior to test-var does not match the binding of var at macro definition:

(let ((var 1)) (test-var var))

However the following example has me puzzled:

(define var 'new-var)
(test-var var)

In Chicken Scheme, this evaluates to new-var. I would have expected it to be no-match for the same reasons as the previous (let) example. I thought that perhaps this was an issue with using define twice, but the result is still new-var even if I use (set! var 'new-var)

Does anyone have any insight as to what is going on here? What should happen per R5RS?

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284

1 Answers1

6

This is the usual trick that Schemes have when dealing with redefinitions on the REPL -- treating them as a mutation for the existing binding. So the second define is not really creating a new binding, and instead it just set!s the existing one.

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • Interesting... although this behavior occurs not just on the REPL but also when running via the interpreter or even a compiled version of the code. – Justin Ethier Nov 03 '11 at 18:31
  • So is it correct to say that this is not specified behavior, but most schemers would expect it to work this way? – Justin Ethier Nov 03 '11 at 18:37
  • Well, by "REPL" I mean any use of "the implicit global namespace", in contrast to using a module system where such redefinitions are usually forbidden. – Eli Barzilay Nov 03 '11 at 18:37
  • If you want to be picky, then R⁵RS says: “At the top level of a program, a definition `(define )` has essentially the same effect as the assignment expression `(set! )` if `` is bound.”. So I'd guess that schemers would expect this. But working without a module system is fairly outdated, and code that depends on the toplevel should be restricted to quick games and debugging... At least IMO. – Eli Barzilay Nov 03 '11 at 18:44