Presentation is loading. Please wait.

Presentation is loading. Please wait.

Defining Macros in Lisp

Similar presentations


Presentation on theme: "Defining Macros in Lisp"— Presentation transcript:

1 Defining Macros in Lisp
Extensibility: A language is extensible if the language can be extended. New Lisp control structures can be created using macros. Common Lisp’s macros are uniquely powerful, and warrant special attention. A macro form is evaluated in a special way: First the macro form is expanded by applying the macro-expansion function (given in the definition) to the arguments. Then the resulting expression is evaluated again. CSE S. Tanimoto Macros

2 CSE 341 -- S. Tanimoto Macros
Example: NULLIFY > (setq x 5) 5 > x > (defmacro nullify (symbol) (list 'setq symbol 'nil) ) NULLIFY > (nullify x) NIL CSE S. Tanimoto Macros

3 Macro Expansion for NULLIFY
By defining the macro NULLIFY, we have actually defined a function, but it’s not named NULLIFY. It’s called the macro expansion function for NULLIFY. When the macro NULLIFY is called, its macro expansion function is applied to the macro argument. And then that result is evaluated. We can see the intermediate result if we use the built-in function MACROEXPAND. > (macroexpand '(nullify total)) (SETQ TOTAL NIL) T ; Two values are returned. ; The first is the expansion itself. ; Second, we have T, since a macro form was expanded. CSE S. Tanimoto Macros

4 CSE 341 -- S. Tanimoto Macros
Macro Call Evaluation (nullify total) 1. The arguments (unevaluated) are passed to the macro expansion function. SYMBOL gets as its binding the symbol TOTAL. 2. The expansion function is applied. Any macro forms within the expansion are themselves expanded. (SETQ TOTAL NIL) 3. The result of expansion is itself evaluated. NIL CSE S. Tanimoto Macros

5 CSE 341 -- S. Tanimoto Macros
Example: IF-N-Z-P Let us now try to create a macro that will evaluate an arithmetic expression and then, depending on whether the value was negative, zero, or positive, evaluate one of three corresponding expressions. (defmacro if-n-z-p (numexpr negform zeroform posform) (list 'cond (list (list '< (eval numexpr) 0) negform) (list (list '= (eval numexpr) 0) zeroform) (list (list '> (eval numexpr) 0) posform) (list t '(print 'error)) ) ) CSE S. Tanimoto Macros

6 Macro Expansion: IF-N-Z-P
> (macroexpand '(if-n-z-p (* 3 -5) -35 'zero 37)) (IF (< -15 0) -35 (IF (= -15 0) 'ZERO (IF (> -15 0) 37 (PRINT 'ERROR)))) T Note that COND, which is implemented as a macro in GCL, was expanded, too. The macro expansion for this macro is a little inefficient, because the condition is always evaluated 3 times. We could rewrite the macro to perform the expansion once, save the value in a local variable, and access it three times. But, what should we name the variable? The safe thing to do is use GENSYM to synthesize a unique symbol and use it. (We’ll return to this later.) CSE S. Tanimoto Macros

7 Example: PUSH (actually built-in)
(defmacro push (element stack) (list 'if (list 'null stack) (list 'setq stack (list 'quote (list element))) (list 'cons element stack)) ) ) CSE S. Tanimoto Macros

8 Macro Expansion for PUSH
> (macroexpand '(push 5 s)) (IF (NULL S) (SETQ S '(5)) (SETQ S (CONS 5 S))) T ; again, the 2nd value is T ; since a macro form was expanded CSE S. Tanimoto Macros

9 Full Macro-form Evaluation
First the form is fully expanded, and then the resulting form is evaluated. > (setq s nil) NIL > (push 5 s) (5) > (push '(next element) s) ((NEXT ELEMENT) 5) CSE S. Tanimoto Macros

10 CSE 341 -- S. Tanimoto Macros
Example: TWICE Takes any number of forms and evaluates them all once and then all again. > (defmacro twice (&rest forms) > (append '(progn) forms forms) ) TWICE > (twice (format t "Macros are powerful~%") > (format t "Aren’t they?~%") ) Macros are powerful Aren’t they? NIL > CSE S. Tanimoto Macros

11 CSE 341 -- S. Tanimoto Macros
Example: AVERAGE Takes two numeric arguments and returns the mean. > (defmacro average (num1 num2) > (list '/ (list '+ (eval num1) (eval num2)) > ) ) AVERAGE > (macroexpand '(average 2 (* 5 4))) (/ (+ 2 20)) T > (average 2 (* 5 4)) 11 Arguments to macros are not automatically evaluated, as they are in function calls. In this example, there is no advantage to using a macro. CSE S. Tanimoto Macros

12 CSE 341 -- S. Tanimoto Macros
Example: SET-TO-ONE Takes any number of arguments, which must be symbols, and gives each the value 1. (defmacro set-to-one (&rest symbols) (append '(progn) (mapcar #'(lambda (s) (list 'setq s 1)) symbols))) > (macroexpand '(set-to-one x y z)) (PROGN (SETQ X 1) (SETQ Y 1) (SETQ Z 1)) T > (set-to-one x y z) 1 > y CSE S. Tanimoto Macros

13 Backquote and Comma Syntax
Allows the body of a macro to look like the expanded form. (defmacro push (element stack) ‘(if (null ,stack) (setq ',stack '(,element)) (setq ,stack (cons ,element ,stack)) ) ) >(macroexpand '(push 5 s)) (IF (NULL S)(SETQ 'S '(5))(SETQ S (CONS 5 S))) T Backquote is like QUOTE but it allows subexpressions preceded by a comma to be evaluated. CSE S. Tanimoto Macros

14 CSE 341 -- S. Tanimoto Macros
Example: ENQUEUE Like PUSH, but puts the new element at the end of the list. (defmacro enqueue (item lst) ‘(if (null ,lst) (setq ',lst '(,item)) (nconc ,lst (list ,item)) ) ) > (setq q '(a b c)) (A B C) > (enqueue 'd q) (A B C D) CSE S. Tanimoto Macros

15 CSE 341 -- S. Tanimoto Macros
Example: SELECT Each clause is a list that begins with a value that might equal that of OBJECT. These value are tested in turn, and the first one that is equal to OBJECT has its remaining clause elements evaluated, and the value of the last of these is returned. > (select 5 (4 "too small") (5 "just right" "five") (6 "six") ) "five" CSE S. Tanimoto Macros

16 CSE 341 -- S. Tanimoto Macros
Example: SELECT Note that the backquote doesn’t have to be at top-level. Also note the use of the dot (.) which means that the list that follows should be spliced into the current list. (defmacro select (object &rest clauses) (append '(cond) (mapcar #'(lambda (clause) `((equal (first ',clause) ,object) . ,(rest clause)) ) clauses))) CSE S. Tanimoto Macros

17 A Better Version of IF-N-Z-P
Let’s improve this macro so that: 1. It evaluates the test expression only once; 2. It uses a temporary symbol for its local variable to avoid the possibility of “Variable Capture.” (defmacro if-n-z-p (expr f1 f2 f3) (let ((val (gensym))) `(let ((,val ,expr)) (cond ((minusp ,val) ,f1) ((zerop ,val) ,f2) ((plusp ,val) ,f3) ) ) ) ) GENSYM creates a new symbol, distinct from all others currently in use. This is protection against the possibility of a “variable-capture” bug. CSE S. Tanimoto Macros

18 Testing the New IF-N-Z-P
> (macroexpand > '(if-n-z-p (- x 3) (- x 1) x (+ x 5)) ) (LET ((#:G1019 (- X 3))) (COND ((MINUSP #:G1019) (- X 1)) ((ZEROP #:G1019) X) ((PLUSP #:G1019) (+ X 5)))) T > (setq x -5) -5 > (if-n-z-p (- x 3) (- x 1) x (+ x 5)) -6 CSE S. Tanimoto Macros

19 What if we didn’t use GENSYM?
(defmacro if-n-z-p-alt (expr f1 f2 f3) (let ((val 'x)) `(let ((,val ,expr)) (cond ((minusp ,val) ,f1) ((zerop ,val) ,f2) ((plusp ,val) ,f3) ) ) ) ) > (macroexpand > '(if-n-z-p-alt (- x 3) (- x 1) x (+ x 1))) (LET ((X (- X 3))) (COND ((MINUSP X) (- X 1)) ((ZEROP X) X) ((PLUSP X) (+ X 1)))) T > (if-n-z-p-alt (- x 3) (- x 1) x (+ x 1))) -9 CSE S. Tanimoto Macros

20 Simpler Version with the Same Problem
(defmacro if-n-z-p-alt2 (expr f1 f2 f3) `(let ((x ,expr)) (cond ((minusp x) ,f1) ((zerop x) ,f2) ((plusp x) ,f3) ) ) ) Even though a new binding of X is created when the macro expansion is executed, any use of X in f1, f2, or f3 will end up referencing this binding rather than the global binding (variable capture). CSE S. Tanimoto Macros

21 CSE 341 -- S. Tanimoto Macros
Language Extension A new control structure, such as SELECT, is a good example of extending a language. Most languages allow user-defined functions, which provide a first level of language extension. By providing a coherent set of extensions to Lisp, typically containing both macro and function definitions, you can create an embedded language (EL). If you need a domain-specific language, an EL may be the way to go, because: The EL takes advantage of its host language, Lisp, for its basic syntax, parsing, and for handling lots of generic functionality. Example domains: knowledge representation, automatic theorem proving, text-processing, combinatorics, gene sequence processing. CSE S. Tanimoto Macros

22 CSE 341 -- S. Tanimoto Macros
Remarks Lisp macros offer a way to extend the language or build an embedded language. Lisp macros are unusually powerful, because the transformation of the macro call into the macro expansion can use the full power of the Lisp runtime system. Most other languages with macro facilities (such as C) can only perform textual substitution and limited expression evaluation. CSE S. Tanimoto Macros


Download ppt "Defining Macros in Lisp"

Similar presentations


Ads by Google