user22919
user22919

Reputation: 33

How do defines and syntax macros interact in Racket?

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 defines that use them behave differently to defines 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

Answers (1)

Sorawee Porncharoenwase
Sorawee Porncharoenwase

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

Related Questions