Macros in Lisp Builtin macros such as SETF
Macros in Lisp Built-in macros such as SETF can be used like special forms. (setf pair (cons 'banana 'split)) (BANANA. SPLIT) (setf (rest pair) 'republic) (BANANA. REPUBLIC) A macro can do many things that functions can do, plus more. CSE 415 -- (c) S. Tanimoto, 2001 Macros 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. 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 415 -- (c) S. Tanimoto, 2001 Macros 2
Example: PUSH (actually built-in) > (defmacro push (element stack) (list 'if (list 'null stack) (list 'setq stack (list 'quote (list element))) (list 'setq stack (list 'cons element stack)) ) ) CSE 415 -- (c) S. Tanimoto, 2001 Macros 3
Macro Expansion The macro expansion function is applied to the macro arguments. We can see these intermediate results if we use the built-in function MACROEXPAND. > (macroexpand '(push 5 s)) (IF (NULL S) (SETQ S '(5)) (SETQ S (CONS 5 S))) T ; 2 nd value is T since a macro form was expanded CSE 415 -- (c) S. Tanimoto, 2001 Macros 4
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 415 -- (c) S. Tanimoto, 2001 Macros 5
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 1 CSE 415 -- (c) S. Tanimoto, 2001 Macros 6
Example: TWICE Takes any number of forms and evaluates them all once and then all again. > (defmacro twice (&rest forms) (append '(progn) forms) ) TWICE > (twice (format t "Macros are powerful~%") (format t "Aren’t they? ~%") ) Macros Aren’t NIL > are powerful they? CSE 415 -- (c) S. Tanimoto, 2001 Macros 7
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 415 -- (c) S. Tanimoto, 2001 Macros 8
Example: ENQUEUE Like PUSH, but puts the new element at the end of the list. > (defmacro enqueue (item lst) ‘(if (null , lst) (set ', lst '(, item)) (nconc , lst (list , item)) ) ) > (setq q '(a b c)) (A B C) > (enqueue 'd q) (A B C D) CSE 415 -- (c) S. Tanimoto, 2001 Macros 9
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 415 -- (c) S. Tanimoto, 2001 Macros 10
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 415 -- (c) S. Tanimoto, 2001 Macros 11
- Slides: 11