Reputation: 33
I'm new to Racket and there's something about syntax macros I don't understand. I have these two programs:
This one, which executes correctly:
#lang racket
(define-syntax-rule (create name) (define name 2))
(create x)
(displayln (+ x 3))
And this one, which complains that the identifier x
is unbound:
#lang racket
(define-syntax-rule (create) (define x 2))
(create)
(displayln (+ x 3))
With a naive substitution approach (such as C/C++ macros) these two programs would behave identically, but evidently they do not. It seems that identifiers that appear in the invocation of a syntax macro are somehow "special" and define
s that use them behave differently to define
s that do not. Additionally, there is the struct
syntax macro in the Racket standard library which defines several variables that are not explicitly named in its invocation, for example:
(struct employee (first-name last-name))
Will define employee?
and employee-first-name
, neither of which were directly named in the invocation.
What is going on here, and it can be worked around so that I could create a custom version of struct
?
Upvotes: 1
Views: 176
Reputation: 6502
The problem with the naive substitution is unintentional capturing. Racket macros by default are hygienic, which means it avoid this problem. See https://en.wikipedia.org/wiki/Hygienic_macro for more details.
That being said, the macro system supports unhygienic macros too. struct
is an example of an unhygienic macro. But you need to put a bit more effort to get unhygienic macros working.
For example, your second version of create
could be written as follows:
#lang racket
(require syntax/parse/define)
(define-syntax-parse-rule (create)
#:with x (datum->syntax this-syntax 'x)
(define x 2))
(create)
(displayln (+ x 3))
Upvotes: 1