Syntax-Rules

Syntax-Rules

Robbert Haarman

2010-12-11


Introduction

The Revised(5) Report on the Algorithmic Language Scheme specifies hygienic macros using the syntax-rules mechanism. These macros are called &ldquot;hygienic&rdquot;, because they do not allow for variable capture the way defmacro macros do. The general consensus is that this makes them less powerful, but also less tricky to write.

Syntax-rules macros, being in the standard, are supported by all up to date Scheme implementations, although some of them may require extensions to be installed or loaded (e.g. SCM needs to be started with -r macro).


Examples

Syntax-rules macros are defined in a way similar to functions, using define-syntax or let-syntax to bind them to a name (analogous to define or let), and syntax-rules to actually define the macro (analogous to lambda). However, the macro expansion is very different from function evaluation, as it is based on pattern matching. A few simple examples:

; simply return what was passed in
(define-syntax id
	(syntax-rules ()
		((id x) x)))

; Do something twice
(define-syntax twice
	(syntax-rules ()
		((twice x) (begin x x))))

So how does syntax-rules work? Basically, it takes a list of clauses, each of which contains a pattern followed by a list. If the pattern matches, the list is returned. The patterns above consist of two symbols, the first of which would match the name of the macro, and the second of which would match the first argument.

It is important to understand that these variables can have any name we care to give them, and this bears no relation to any names outside the syntax-rules form. This is what makes syntax-rules macros hygienic; even if there were an outside variable named x, it would not conflict with the xs used inside the macros. Also note that naming the first pattern variable after the macro is just a convention; it is not enforced at all.

The first argument to syntax-rules is a list of things to match literally. Any symbol occurring in that list will not be treated as a pattern variable, but will have to occur literally in the input. The following macro is intended to clarify pattern matching and the use of literal symbols. It emulates cond using if and begin:

(define-syntax kond
	(syntax-rules (else)
		((kond (else code ...))
			(begin code ...))
		((kond (condition code ...))
			(if condition (begin code ...)))
		((kond (condition code ...) alts ...)
			(if condition
				(begin code ...)
				(kond alts ...)))))

Note that the ... are actually part of the pattern language. I hope you understand what it all means. At any rate, it should be clear that macros allow cond to be implemented in terms of if and begin. Similarly, let can be implemented using lambda, and let* and letrec using let, etc. In the end, it turns out that only a few constructs are fundamental to Scheme, the rest can all be implemented using functions and macros.

Valid XHTML 1.1! Valid CSS! Viewable with Any Browser