A Few Principles of Macro Design Dave Herman / David Van Horn

Preview:

DESCRIPTION

A Few Principles of Macro Design Dave Herman / David Van Horn. Motivated by theory…. What is hygiene?. …but hopefully useful. Quotation, which thus interrupts the referential force of a term, may be said to fail of referential transparency. — Quine, Word and Object (1960). - PowerPoint PPT Presentation

Citation preview

1

A Few Principles of Macro DesignDave Herman / David Van Horn

2

Motivated by theory…

What is hygiene?

…but hopefully useful

3

— Quine, Word and Object (1960)

Quotation, which thus interrupts the referential force of aterm, may be said to fail of referential transparency.

4

How to substitute equals for equals?1. Hygiene alone doesn’t provide reasoning principles for

macros.Where did we go wrong?

2. Disciplined macros make reasoning possible through interfaces.What can we do about it?

5

Part I. Fexprs

6

Fexprs

> (define f (fexpr (form env) (printf "input: ~a\n" form) (eval (car form) env)))> (f (+ 2 3))input: ((+ 2 3))5

7

The trouble with fexprs

(f (+ 2 3))

(f 5)

8

Why this is bad (Pitman, Wand)• Compilers: can’t do source-to-source

optimizations• Programmers: refactoring is brittle

(+ 2 3) ≠ 5(lambda (x) x) ≠ (lambda (y) y)

(list 1) ≠ (cons 1 '())

9

Same w/macros—at compile-time

(m (+ 2 3))

(m 5)

10

Macros are introspective

Even syntax-rules macros can:• Destructure their input• Compare identifiers• Copy identifiers into different contexts• Quote their input

(see Petrofsky ‘01, Kiselyov ‘02)

11

(sexp=? (+ 2 3) 5 "true" "false")

(sexp=? (+ 2 3) (+ 2 3) "true" "false")

A macrological microscope

(sexp=? s1 s2 tk fk)

(+ 2 3) "true"

5 "false"

12

Consequence

No interesting equivalence for unexpanded Scheme respects all possible contexts.

Referentially opaque contexts:

(sexp=? s □ tk fk)(quote □)

Turing-completeness: undecidable whether such contexts will arise during expansion.

13

Are these programs the same?

(let ((x 42)) x)

(let ((y 42)) y)

14

What if let is a macro?

(define-syntax let (syntax-rules () ((let ((name val) ...) body1 body2 ...) ((lambda (name ...) body1 body2 ...) val ...)) ((let tag ((name val) ...) body1 body2 ...) ((letrec ((tag (lambda (name ...) body1 body2 ...))) tag) val ...))))

15

Expand it to understand it

(let ((x 42)) x) ((lambda (x) x) 42) ((lambda (x) x[x := x]) 42) ((lambda (x) x) 42)

(let ((y 42)) y) ((lambda (y) y) 42) ((lambda (y) y[y := y]) 42) ((lambda (y) y) 42)

16

Expand it to understand it

17

Syntactic abstraction

• We don’t force clients of procedures to step through evaluation.

• We don’t want to force clients of macros to, either!

• Clients shouldn’t—and don’t—rely exclusively on tools.

• Extending Scheme new equivalences, contexts.• Good macros document this through their

interfaces.

18

Part II. Interfaces

19

The specification of let

20

The interface of let (take 1)

(let ((ident expr) ...) expr) :: expr

New expression-context forms:

(let ((x1 e1) ... (xi □) (xi+1 ei+1) ...) e)

(let ((x e) ...) □)

21

Principle: opaque subexpressions;; (peek expr) :: expr(define-syntax peek (syntax-rules (lambda) ((_ (lambda (x ...) e ...)) (begin e ...)) ((_ e) e)))

(peek id)≠

(peek (lambda (x) x))

id

22

The specification of let

23

The interface of let (take 2)

(let ((x:ident expr) ...) expr[x ...]) :: expr

e1 = e′1 z fresh e2[x := z] = e′2[x′ := z]

(let ((x e1)) e2) = (let ((x′ e′1)) e′2)

• Such a relation will not respect all contexts• But perhaps contexts from macros with good

interfaces

24

Principle: opaque variables

;; (lambda* (x:ident) expr[x]) :: expr(define-syntax lambda* (syntax-rules (foo) ((_ (foo) e) (error 'm "I don't like the name foo")) ((_ (x) e) (lambda (x) e))))

(lambda* (a) a)≠

(lambda* (foo) foo)

25

Principle: consistent identifiers;; (set-lambda (x:ident) expr[x]) :: expr(define-syntax set-lambda (syntax-rules () ((_ (x) e) (begin (set! x e) (lambda (x) e)))))

(set-lambda (x) x)≠

(set-lambda (cons) cons)

26

Principles, not laws

(define frame (subclass window (inherit width height) ;; … (define area (* width height)) ))

27

Principles, not laws

(define frame (subclass window (inherit (width as window:width) (height as window:height)) ;; … (define area (* window:width window:height)) ))

28

Design for program equivalences• Rational extension of program contexts.• Rational extension of program equivalences.

(let ((x (+ 2 3))) x)(let ((x 5)) x)(let ((y 5)) y)

29

Moral

• Like fexprs, even hygienic macros provide very fine syntactic introspection.

• Syntactic abstractions should be comprehensible without inspecting their expansion.

• Designing macros with good interfaces allows programmers to reason about unexpanded programs.

Thank you.

Recommended