Scheme-Style Macros: Patterns and Lexical Scope

Similar documents
Why Macros? Scheme-Style Macros: Patterns and Lexical Scope. Macros versus Arbitrary Program Generators. Macros versus Arbitrary Program Generators

It s Turtles All the Way Up: Self-Extensible Programming Languages in PLT Scheme

Syntactic Abstraction in Component Interfaces

Racket: Macros. Advanced Functional Programming. Jean-Noël Monette. November 2013

Macros that Work Together

Macros that Work Together

A Few Principles of Macro Design

Binding as Sets of Scopes

From Macrogeneration to Syntactic Abstraction

Title. Authors. Status. 1. Abstract. 2. Rationale. 3. Specification. R6RS Syntax-Case Macros. Kent Dybvig

Functional Programming. Pure Functional Languages

Functional Programming. Pure Functional Languages

Binding as Sets of Scopes

Evaluating Scheme Expressions

Functional Programming

Kent Dybvig, Will Clinger, Matthew Flatt, Mike Sperber, and Anton van Straaten

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

Syntactic Abstraction in Scheme

Hygiene for the Unhygienic

Some Naughty Bits. Jeremy Brown. January 7-8, 2003

Languages as Libraries

CS 314 Principles of Programming Languages

Parser Tools: lex and yacc-style Parsing

Macro Debugger. Version 5.1. Ryan Culpepper. February 14, 2011

Parser Tools: lex and yacc-style Parsing

Racket: Modules, Contracts, Languages

Extensible Pattern Matching

Macros. Pat Hanrahan. CS448h Fall 2015

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program?

CS 360 Programming Languages Interpreters

6.945 Adventures in Advanced Symbolic Programming

Concepts of programming languages

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

Implicit Phasing for R6RS Libraries

An Optimized R5RS Macro Expander. Sean Reque

CSCE 314 Programming Languages. Type System

Functional Programming. Big Picture. Design of Programming Languages

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

Macro Debugger: Inspecting Macro Expansion

Programming Languages: Application and Interpretation

FP Foundations, Scheme

Syntax: Meta-Programming Helpers

From Macros to Reusable Generative. Rice University. Seattle University. Seattle, WA , USA

Design Issues. Subroutines and Control Abstraction. Subroutines and Control Abstraction. CSC 4101: Programming Languages 1. Textbook, Chapter 8

CS450: Structure of Higher Level Languages Spring 2018 Assignment 7 Due: Wednesday, April 18, 2018

How to Write Seemingly Unhygienic and Referentially Opaque Macros with Syntax-rules

Revised 5 Report on the Algorithmic Language Scheme

hexpressioni ::= hvariablei j hself evaluating literali j (quote hdatumi) j (lambda (hvariablei*) hexpressioni + ) j (if hexpressioni hexpressioni hex

Programming Languages: Application and Interpretation

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

Kent Dybvig, Will Clinger, Matthew Flatt, Mike Sperber, and Anton van Straaten

CSCC24 Functional Programming Scheme Part 2

CSE 341: Programming Languages

A Stepper for Scheme Macros

Debugging Macros. Ryan Culpepper. Matthias Felleisen. Abstract. 1. The Power of Macros. Northeastern University

COP4020 Programming Assignment 1 - Spring 2011

A pattern-matcher for αkanren -or- How to get into trouble with CPS macros

Macros That Work. William Clinger Department of Computer Science University of Oregon

COP4020 Programming Languages. Subroutines and Parameter Passing Prof. Robert van Engelen

CS 345. Functions. Vitaly Shmatikov. slide 1

Refining Syntactic Sugar: Tools for Supporting Macro Development

A Self-Hosting Evaluator using HOAS

Functional Programming - 2. Higher Order Functions

Lexical Considerations

Functional Programming

CS61A Midterm 2 Review (v1.1)

JRM s Syntax-rules Primer for the Merely Eccentric

Semantic Analysis and Type Checking

Languages as Libraries

Implementing R7RS on an R6RS Scheme system

Functional Programming. Pure Functional Programming

From Syntactic Sugar to the Syntactic Meth Lab:

Publications related to Chez Scheme

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

The Environment Model. Nate Foster Spring 2018

Lecture 09: Data Abstraction ++ Parsing is the process of translating a sequence of characters (a string) into an abstract syntax tree.

SYNTACTIC EXTENSION FOR LANGUAGES WITH IMPLICITLY DELIMITED AND INFIX SYNTAX

CS 242. Fundamentals. Reading: See last slide

Typed Scheme From Scripts to Programs. Sam Tobin-Hochstadt Northeastern University

Programmiersprachen (Programming Languages)

Lambda Calculus see notes on Lambda Calculus

A Theory of Hygienic Macros

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

A Brief Introduction to Scheme (I)

Lambda Calculus. Gunnar Gotshalks LC-1

Lecture 9: Parameter Passing, Generics and Polymorphism, Exceptions

FORTRAN. FORTRAN Concepts/Contributions

Dissertation Proposal

Scheme Quick Reference


CSE341: Programming Languages Lecture 15 Macros. Zach Tatlock Winter 2018

What is a macro. CSE341: Programming Languages Lecture 15 Macros. Example uses. Using Racket Macros. Zach Tatlock Winter 2018

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

CS 314 Principles of Programming Languages

Constraint-based Analysis. Harry Xu CS 253/INF 212 Spring 2013

Comp 311: Sample Midterm Examination

Lambda Calculus LC-1

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

Introduction to Scheme

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Transcription:

Scheme-Style Macros: Patterns and Lexical Scope Matthew Flatt University of Utah 1

Why Macros? Language designers have to stop somewhere (544 pages) No language can provide every possible useful construct Macros let a programmer fill in gaps 2-3

Macros versus Arbitrary Program Generators Macros extend the language without extending the tool chain Jack (YACC for Java) requires a new tool chain: Grammar.jack Run.java jack Grammar.class javac Run.class Interp.jar Jack doesn't play nice with all Java environments 4-6

Macros versus Arbitrary Program Generators Macros extend the language without extending the tool chain Scheme-YACC is a macro: SYACC.scm Grammar.scm Run.scm mzc Interp.exe SYACC automatically plays nice with all Scheme environments... in principle 7-9

Macros and Libraries Macros = hook in tool chain to extend a language Scheme ensures that macros play nice with the tool chain Some libraries include macros Scheme ensures that library macros play nice with each other 10-11

Macros In General Pattern-Based Macros Scheme macro basics Extended Example Lexical Scope General Transformers 12

Pattern-Based Macros Most popular API for macros: patterns #define swap(x, y) (tmp=y, y=x, x=tmp) swap(c.red, d->blue) (tmp=d->blue, d->blue=c.red, c.red=tmp) + Relatively easy for programmers to understand + Obvious hook into the tool chain - Pure patterns can't easily express much...but possibly more than you think 13-15

Scheme Macro Basics (define-syntax swap ) define-syntax indicates a macro definition 16

Scheme Macro Basics (define-syntax swap (syntax-rules () )) syntax-rules means a pattern-matching macro () means no keywords in the patterns 17

Scheme Macro Basics (define-syntax swap (syntax-rules () [pattern template]... [pattern template])) Any number of patterns to match Produce result from template of first match 18

Scheme Macro Basics (define-syntax swap (syntax-rules () ((swap a b) ))) Just one pattern for this macro: (swap a b) Each identifier matches anything in use (swap x y) a is x b is y (swap 9 (+ 1 7)) a is 9 b is (+ 1 7) 19

Scheme Macro Basics (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) Bindings substituted into template to generate the result (swap x y) (let ([tmp y]) (set! y x) (set! x tmp)) (swap 9 (+ 1 7)) (let ([tmp (+ 1 7)]) (set! (+ 1 7) 9) (set! 9 tmp)) 20

Lexical Scope (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) What if we swap a variable named tmp? (let ([tmp 5] [other 6]) (swap tmp other))? (let ([tmp 5] [other 6]) (let ([tmp other]) (set! other tmp) (set! tmp tmp))) 21

Lexical Scope (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) What if we swap a variable named tmp? (let ([tmp 5] [other 6]) (swap tmp other))? (let ([tmp 5] [other 6]) (let ([tmp other]) (set! other tmp) (set! tmp tmp))) This expansion would violate lexical scope 22

Lexical Scope (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) What if we swap a variable named tmp? (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 5] [other 6]) (let ([tmp 1 other]) (set! other tmp) (set! tmp tmp 1 ))) Scheme renames the introduced binding Details later... 23

Lexical Scope: Local Bindings Lexical scope means that local macros work, too: (define (f x) (define-syntax swap-with-arg (syntax-rules () ((swap-with-arg y) (swap x y)))) (let ((z 12) (x 10)) ; Swaps z with original x: (swap-with-arg z)) ) Details later... 24

Matching Sequences Some macros need to match sequences (rotate x y) (rotate red green blue) (rotate front-left rear-right front-right rear-left) 25

Matching Sequences (define-syntax rotate (syntax-rules () ((rotate a) (void)) ((rotate a b c...) (begin (swap a b) (rotate b c...)))))... in a pattern: multiple of previous sub-pattern (rotate x y z w) c is z w... in a template: multiple instances of previous sub-template (rotate x y z w) (begin (swap x y) (rotate y z w)) 26-27

Matching Sequences (define-syntax rotate (syntax-rules () ((rotate a c...) (shift-to (c... a) (a c...))))) (define-syntax shift-to (syntax-rules () ((shift-to (from0 from...) (to0 to...)) (let ((tmp from0)) (set! to from)... (set! to0 tmp)) )))... maps over same-sized sequences... duplicates constants paired with sequences 28

Identifier Macros The swap and rotate names work only in an "application" position (swap x y) (let ((tmp y)) ) (+ swap 2) syntax error An identifier macro works in any expression position...or as a set! target clock (get-clock) (+ clock 10) (+ (get-clock) 10) (clock 5) ((get-clock) 5) (set! clock 10) (set-clock! 10) 29-31

Identifier Macros (define-syntax clock (identifier-syntax (clock (get-clock)) ((set! clock e) (put-clock! e)))) PLT Scheme provides syntax-id-rules: (define-syntax clock (syntax-id-rules (set!) ((set! clock e) (put-clock! e)) ((clock a...) ((get-clock) a...)) (clock (get-clock)))) set! is designated as a keyword syntax-rules is a special case of syntax-id-rules with errors in the first and third cases 32-33

Macro-Generating Macros If we have many identifiers like clock... (define-syntax define-get/put-id (syntax-rules () ((define-get/put-id id get put!) (define-syntax id (identifier-syntax (id (get)) ((set! id e) (put! e))))))) (define-get/put-id clock get-clock put-clock!) 34-35

Macros In General Pattern-Based Macros Extended Example Using patterns and macro-generating macros Lexical Scope General Transformers 36

Extended Example Let's add call-by-reference definitions to Scheme (define-cbr (f a b) (swap a b)) (let ([x 1] [y 2]) (f x y) x) ; should produce 2 37

Extended Example Expansion of first half: (define-cbr (f a b) (swap a b)) (define (do-f get-a get-b put-a! put-b!) (define-get/put-id a get-a put-a!) (define-get/put-id b get-b put-b!) (swap a b)) 38

Expansion of second half: Extended Example (let ([x 1] [y 2]) (f x y) x) (let ([x 1] [y 2]) (do-f (lambda () x) (lambda () y) (lambda (v) (set! x v)) (lambda (v) (set! y v))) x) 39

Call-by-Reference Setup How the first half triggers the second half: (define-syntax define-cbr (syntax-rules () ((_ (id arg...) body) (begin (define-for-cbr do-f (arg...) () body) (define-syntax id (syntax-rules () ((id actual (......)) (do-f (lambda () actual) (......) (lambda (v) (set! actual v)) (......)) ))))))) 40

Remaining expansion to define: Call-by-Reference Body (define-for-cbr do-f (a b) () (swap a b)) (define (do-f get-a get-b put-a! put-b!) (define-get/put-id a get-a put-a!) (define-get/put-id b get-b put-b!) (swap a b)) How can define-for-cbr make get- and put-! names? 41-42

A name-generation trick: Call-by-Reference Body (define-syntax define-for-cbr (syntax-rules () ((define-for-cbr do-f (id0 id...) (gens...) body) (define-for-cbr do-f (id...) (gens... (id0 get put)) body)) ((define-for-cbr do-f () ((id get put)...) body) (define (do-f get... put...) (define-get/put-id id get put)... body) ))) 43

Call-by-Reference Body More accurate description of the expansion: (define-for-cbr do-f (a b) () (swap a b)) (define (do-f get 1 get 2 put 1 put 2 ) (define-get/put-id a get 1 put 1 ) (define-get/put-id b get 2 put 2 ) (swap a b)) 44

Complete Code to Add Call-By-Reference (define-syntax define-cbr (syntax-rules () ((_ (id arg...) body) (begin (define-for-cbr do-f (arg...) () body) (define-syntax id (syntax-rules () ((id actual (......)) (do-f (lambda () actual) (......) (lambda (v) (set! actual v)) (......)) ))))))) (define-syntax define-get/put-id (syntax-rules () ((define-get/put-id id get put!) (define-syntax id (identifier-syntax (id (get)) ((set! id e) (put! e))))))) (define-syntax define-for-cbr (syntax-rules () ((define-for-cbr do-f (id0 id...) (gens...) body) (define-for-cbr do-f (id...) (gens... (id0 get put)) body)) ((define-for-cbr do-f () ((id get put)...) body) (define (do-f get... put...) (define-get/put-id id get put)... body) ))) Relies on lexical scope and macro-generating macros 45

Macros In General Pattern-Based Macros Extended Example Lexical Scope Making it work General Transformers 46

Lexical Scope (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) What if we swap a variable named tmp? (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 5] [other 6]) (let ([tmp 1 other]) (set! other tmp) (set! tmp tmp 1 ))) Scheme renames the introduced binding 47

Reminder: Lexical Scope for Functions (define (app-it f) (let ([x 12]) (f x))) (let ([x 10]) (app-it (lambda (y) (+ y x)))) 48

Reminder: Lexical Scope for Functions (define (app-it f) (let ([x 12]) (f x))) (let ([x 10]) (app-it (lambda (y) (+ y x)))) (let ([x 10]) (let ([x 12]) ((lambda (y) (+ y x)) x))) Bad capture 49

Reminder: Lexical Scope for Functions (define (app-it f) (let ([x 12]) (f x))) (let ([x 10]) (app-it (lambda (y) (+ y x)))) (let ([x 10]) (let ([z 12]) ((lambda (y) (+ y x)) z))) Ok with α-rename inside app-it 50

Reminder: Lexical Scope for Functions (define (app-it f) (let ([x 12]) (f x))) (let ([x 10]) (app-it (lambda (y) (+ y x)))) (let ([x 10]) (let ([z 12]) ((lambda (y) (+ y x)) z))) Ok with α-rename inside app-it But usual strategy must see the binding... 51

Bindings in Templates (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) Seems obvious that tmp can be renamed 52

Rename tmp if Bindings in Templates (define-syntax swap (syntax-rules () ((swap a b) (let-one (tmp b) (set! b a) (set! a tmp)) ))) (define-syntax let-one (syntax-rules () ((let-one (x v) body) (let ((x v)) body)))) 53-54

Bindings in Templates (define-syntax swap (syntax-rules () ((swap a b) (let-one (tmp b) (set! b a) (set! a tmp)) ))) Cannot rename tmp if (define-syntax let-one (syntax-rules () ((let-one (x v) body) (list 'x v body)))) Scheme tracks identifier introductions, then renames only as binding forms are discovered 55-56

Lexical Scope via Tracking, Roughly (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) Tracking avoids capture by introduced variables (let ([tmp 5] [other 6]) (swap tmp other)) ~ (let ([tmp 5] [other 6]) (let 1 ([tmp 1 other]) (set! 1 other tmp) (set! 1 tmp tmp 1 ))) 1 means introduced by expansion tmp 1 does not capture tmp 57

Lexical Scope via Tracking, Roughly (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) Tracking also avoids capture of introduced variables (let ([set! 5] [let 6]) (swap set! let)) ~ (let ([set! 5] [let 6]) (let 1 ([tmp 1 let]) (set! 1 let set!) (set! 1 set! tmp 1 ))) set! does not capture set! 1 let does not capture let 1 58

Precise Rules for Expansion and Binding (let ([tmp 5] [other 6]) (swap tmp other)) 59

Precise Rules for Expansion and Binding (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 0 5] [other 0 6]) (swap tmp 0 other 0 )) When the expander encounters let, it renames bindings by adding a subscript 60

Precise Rules for Expansion and Binding (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 0 5] [other 0 6]) (swap tmp 0 other 0 )) When the expander encounters let, it renames bindings by adding a subscript If a use turns out to be quoted, the subscript will be erased (let ([x 1]) 'x) (let ([x 1 1]) 'x 1 ) (let ([x 1 1]) 'x) 61

Precise Rules for Expansion and Binding (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 0 5] [other 0 6]) (swap tmp 0 other 0 )) (let ([tmp 0 5] [other 0 6]) (let 1 ([tmp 1 other 0 ]) (set! 1 other 0 tmp 0 ) (set! 1 tmp 0 tmp 1 ))) Then expansion continues, adding superscripts for introduced identifiers 62

Precise Rules for Expansion and Binding (let ([tmp 5] [other 6]) (swap tmp other)) (let ([tmp 0 5] [other 0 6]) (swap tmp 0 other 0 )) (let ([tmp 0 5] [other 0 6]) (let 1 ([tmp 1 other 0 ]) (set! 1 other 0 tmp 0 ) (set! 1 tmp 0 tmp 1 ))) (let ([tmp 0 5] [other 0 6]) (let 1 ([tmp 2 other 0 ]) (set! 1 other 0 tmp 0 ) (set! 1 tmp 0 tmp 2 ))) Again, rename for let but only where superscripts match 63

Precise Rules for Expansion and Binding (let ([set! 5] [let 6]) (swap set! let)) 64

Precise Rules for Expansion and Binding (let ([set! 5] [let 6]) (swap set! let)) (let ([set! 0 5] [let 0 6]) (swap set! 0 let 0 )) 65

Precise Rules for Expansion and Binding (let ([set! 5] [let 6]) (swap set! let)) (let ([set! 0 5] [let 0 6]) (swap set! 0 let 0 )) (let ([set! 0 5] [let 0 6]) (let 1 ([tmp 1 let 0 ]) (set! 1 let 0 set! 0 ) (set! 1 set! 0 tmp 1 ))) 66

Precise Rules for Expansion and Binding (let ([set! 5] [let 6]) (swap set! let)) (let ([set! 0 5] [let 0 6]) (swap set! 0 let 0 )) (let ([set! 0 5] [let 0 6]) (let 1 ([tmp 1 let 0 ]) (set! 1 let 0 set! 0 ) (set! 1 set! 0 tmp 1 ))) (let ([set! 0 5] [let 0 6]) (let 1 ([tmp 2 let 0 ]) (set! 1 let 0 set! 0 ) (set! 1 set! 0 tmp 2 ))) Superscript does not count as a rename, so let and let 1 refer to the usual let 67

Local Macros (define (run-clock get put!) (define-get/put-id clock get put!) (set! clock (add1 clock)) ) (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (set! clock 1 (add1 clock 1 )) ) (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (put 0 2 (add1 (get 03 ))) ) 68-70

Local Macros (define (run-clock get put!) (define-get/put-id clock get put!) (let ((get )) (set! clock (get clock)) ) ) (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (let ((get 0 )) (set! clock 1 (get 0 clock 1 )) ) ) 71-72

Local Macros (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (let ((get 0 )) (set! clock 1 (get 0 clock 1 )) ) ) (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (let ((get 2 )) (set! clock 1 (get 2 clock 1 )) ) ) 73-74

Local Macros (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (let ((get 2 )) (set! clock 1 (get 2 clock 1 )) ) ) (define (run-clock get 0 put! 0 ) (define-get/put-id clock 1 get 0 put! 0 ) (let ((get 2 )) (put! 0 3 (get 2 (get 04 ))) ) ) 75-76

General Strategy Summarized While expanding Primitive binding form: Change subscript in scope for matching names, subscript, and superscripts When looking for binders of a use: Check for matching name and subscript, only After expanding a macro use: Add a superscript to introduced identifiers (macro-generating macros can stack superscripts) 77

Terminology Avoid capture by introduced: hygiene Avoid capture of introduced: referential transparency Together lexical scope Lexically scoped macros play nice together 78

Macros In General Pattern-Based Macros Extended Example Lexical Scope General Transformers Beyond patterns and templates 79

Transformer Definitions In general, define-syntax binds a transformer procedure (define-syntax swap (lambda (stx) )) Argument to transformer is a syntax object: like an S-expression, but with context info 80-81

Primitives for Transformers Primitives deconstruct and construct syntax objects: (stx-car stx) -> stx (stx-cdr stx) -> stx (stx-pair? stx) -> bool (identifier? stx) -> bool (quote-syntax datum) -> stx (bound-identifier=? stx1 stx2) -> bool (free-identifier=? stx1 stx2) -> bool (datum->syntax stx v) -> stx 82

Syntax-Rules as a Transformer syntax-rules is actually a macro (define-syntax swap (syntax-rules...)) (define-syntax swap (lambda (stx) use transformer primitives to match stx and generate result )) 83

Pattern-Matching Syntax and Having It, Too The syntax-case and #' forms combine patterns and arbitrary computation (syntax-case stx-expr () (pattern result-expr)... (pattern result-expr)) #'template syntax-case and #' work anywhere useful for sub-expression matches 84-85

Pattern-Matching Syntax and Having It, Too Actually, syntax-rules is implemented in terms of syntax-case (define-syntax swap (syntax-rules () ((swap a b) (let ((tmp b)) (set! b a) (set! a tmp))))) (define-syntax swap (lambda (stx) (syntax-case stx () ((swap 1 a b) #'(let ((tmp b)) (set! b a) (set! a tmp)))))) 86

Syntax-Case for a Better Swap Macro Check for identifiers before expanding: (define-syntax swap (lambda (stx) (syntax-case stx () ((_ a b) (if (and (identifier? #'a) (identifier? #'b)) #'(let ((tmp b)) (set! b a) (set! a tmp)) (raise-syntax-error 'swap "needs identifiers" stx)))))) 87

Syntax-case for a Better Call-by-Ref Macro Use generate-temporaries to produce a list ids: (define-syntax (define-for-cbr stx) (syntax-case stx () ((_ do-f (id...) body) (with-syntax (((get...) (generate-temporaries #'(arg...))) ((put...) (generate-temporaries #'(arg...)))) #'(define (do-f get... put...) (define-get/put-id id get put)... body) )))) 88

hygiene patterns lexical scope References, Abridged Kohlbecker, Friedman, Felleisen, and Duba "Hygienic Macro Expansion" LFP 1986 Clinger and Rees "Macros That Work" POPL 1991 Dybvig, Hieb, and Bruggeman "Syntactic Abstraction in Scheme" Lisp and Symbolic Computation 1993 splicing scope Waddell and Dybvig "Extending the Scope of Syntactic Abstraction" POPL 1999 phases Flatt "Composable and Compilable Macros" ICFP 2002 89