Macros and Function Generators CS 480/680 – Comparative Languages
Macros2 List Structures When we have a list like this: ’( ) we know the structure looks like this: Likewise, when you create code like this: (+ 2 3) you end up with a structure like this:
Macros3 Creating Code A powerful feature of Scheme is the ability to create code on the fly: (define a ‘(+ 3 2)) (list a a a) >> ((+ 2 3) (+ 2 3) (+ 2 3)) (eval (cons ‘begin (list a a a))) >> 5 begin only returns the result of the last subform evaluated. However, here (+ 2 3) was evaluated three times
Macros4 Macros A Scheme macro is a function that: Produces a list, and then Evaluates the list Differs from an ordinary function, in that the list that is produced is evaluated The macro returns whatever the evaluated list returns
Macros5 Macro Shortcuts Within a macro, you can use a list template: Starts with a backquote: ` Inside the template: ,symbol – replaced by a macro parameter – replaced by a spliced parameter. That is, a parameter with the outer set of parentheses removed
Macros6 A simple example Arguments to lambda are collected in the list: ((display “hi”) (newline)) Template creates: (begin (display “hi”) (newline) (display “hi”) (newline) (display “hi”) (newline)) (require (lib ”defmacro.ss”)) (define-macro do3 (lambda code (do3 (display "hi") (newline)) hi Notice the lack of quotes!
Macros7 A more complicated example Suppose we wanted a function called “when”, that would take as arguments a test and multiple subforms If the test is true, all the subforms are executed Like ‘if’, but: (if (test) (begin (form1) (form2) (form3)… ) )
Macros8 A more complicated example (when (< (pressure tube) 60) (open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube)) Test Subforms
Macros9 A more complicated example (define-macro when (lambda (test. branch) (list 'if test (cons 'begin branch)))) (when (< (pressure tube) 60) (open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube))
Macros10 A more complicated example (define-macro when (lambda (test. branch) (list 'if test (cons 'begin branch)))) test = (when (< (pressure tube) 60) branch = ((open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube))
Macros11 A more complicated example (define-macro when (lambda (test. branch) (list 'if test (cons 'begin branch)))) test = (< (pressure tube) 60) branch = ((open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube)) >> (if (< (pressure tube) 60) (begin (open-valve tube) … )
Macros12 Variable Capture Since a macro is a textual translation, it does not introduce a new local scope! If a macro uses a local variable name (via let) that is the same as a variable of a higher scope, the higher scoped variable cannot be passed as a macro parameter Can leave quite a mess Solution – (gensym) creates a unique symbol name that can be used with,name in a template