Hygienic Macro - Implementations

Implementations

Macro systems that automatically enforce hygiene originated with Scheme. The original algorithm (KFFD algorithm) for a hygienic macro system was presented by Kohlbecker in '86. At the time, no standard macro system was adopted by Scheme implementations. Shortly thereafter in '87, Kohlbecker and Wand proposed a declarative pattern-based language for writing macros, which was the predecessor to the syntax-rules macro facility adopted by the R5RS standard. Syntactic closures, an alternative hygiene mechanism, was proposed as an alternative to Kohlbecker et al.'s system by Bawden and Rees in '88. Unlike the KFFD algorithm, syntactic closures require the programmer to explicitly specify the resolution of the scope of an identifier. In '93, Dybvig et al. introduced the syntax-case macro system, which uses an alternative representation of syntax and maintains hygiene automatically. The syntax-case system can express the syntax-rules pattern language as a derived macro.

The term macro system can be ambiguous because, in the context of Scheme, it can refer to both a pattern-matching construct (e.g., syntax-rules) and a framework for representing and manipulating syntax (e.g., syntax-case, syntactic closures). Syntax-rules is a high-level pattern matching facility that attempts to make macros easier to write. However, syntax-rules is not able to succinctly describe certain classes of macros and is insufficient to express other macro systems. Syntax-rules was described in the R4RS document in an appendix but not mandated. Later, R5RS adopted it as a standard macro facility. Here is an example syntax-rules macro that swaps the value of two variables:

(define-syntax swap! (syntax-rules ((_ a b) (let ((temp a)) (set! a b) (set! b temp)))))

Due to the deficiencies of a purely syntax-rules based macro system, low-level macro systems have also been proposed and implemented for Scheme. Syntax-case is one such system. Unlike syntax-rules, syntax-case contains both a pattern matching language and a low-level facility for writing macros. The former allows macros to be written declaratively, while the latter allows the implementation of alternative frontends for writing macros. The swap example from before is nearly identical in syntax-case because the pattern matching language is similar:

(define-syntax swap! (lambda (stx) (syntax-case stx ((_ a b) (syntax (let ((temp a)) (set! a b) (set! b temp)))))))

However, syntax-case is more powerful than syntax-rules. For example, syntax-case macros can specify side-conditions on its pattern matching rules via arbitrary Scheme functions. Alternatively, a macro writer can choose not to use the pattern matching frontend and manipulate the syntax directly. Using the datum->syntax function, syntax-case macros can also intentionally capture identifiers, thus breaking hygiene. The R6RS Scheme standard adopted the syntax-case macro system.

Syntactic closures and explicit renaming are two other alternative macro systems. Both systems are lower-level than syntax-rules and leave the enforcement of hygiene to the macro writer. This differs from both syntax-rules and syntax-case, which automatically enforce hygiene by default. The swap examples from above are shown here using a syntactic closure and explicit renaming implementation respectively:

;; syntactic closures (define-syntax swap! (sc-macro-transformer (lambda (form environment) (let ((a (close-syntax (cadr form) environment)) (b (close-syntax (caddr form) environment))) `(let ((temp ,a)) (set! ,a ,b) (set! ,b temp)))))) ;; explicit renaming (define-syntax swap! (er-macro-transformer (lambda (form rename compare) (let ((a (cadr form)) (b (caddr form)) (temp (rename 'temp))) `(,(rename 'let) ((,temp ,a)) (,(rename 'set!) ,a ,b) (,(rename 'set!) ,b ,temp))))))

Read more about this topic:  Hygienic Macro