Scheme syntax-rules - Difference in variable bindings between (let) and (define)

498 views Asked by At

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?

1

There are 1 answers

4
Eli Barzilay On BEST ANSWER

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.