Presentation on theme: "A problem with functions: arguments must always have values that can be worked out Whenever we call a function we give it arguments. Lisp then works out."— Presentation transcript:
A problem with functions: arguments must always have values that can be worked out Whenever we call a function we give it arguments. Lisp then works out the values of those arguments, and places those values into the body of the function. (defun min(x y) (if (< x y) x y)) >(min (+ 3 3) (- 5 1)) (Eval is the name of the lisp function that works out the value of an expression.) But what if we don’t want lisp to work out argument values? (eval (+ 3 3)) (eval (if (< 6 4) 6 4))) (eval (– 5 1)) 64 4
Suppose we want a function SET-DEF which takes a variable name and a value as arguments, and does the following: “if this variable has a value, do not change it, but return the value; if it does not yet has a value, assign this value to it, and return that value” > (set-def x 6) 6 > x 6 > (set-def x 12) 6 > x 6 However, trying to define SET-DEF as a simple DEFUN function will fail, since such a function will try to evaluate all its arguments and hence would evaluate the variable name we are trying to alter. If the variable had no value, the function would end with an error message. To do something like this, we need a new construct: a MACRO. Example
Macros and evaluation A macro is a user-definable Lisp procedure which operates by rearranging its arguments into the form of piece of Lisp text, and then getting the system to evaluate that text. Macros are defined using a very similar notation to that used for functions, except that the Lisp keyword DEFMACRO is used instead of DEFUN A Macro is not a function: it does not call eval to work out the values of its arguments. Instead, a macro writes a piece of lisp code (quoting keywords and function names in that code), places its arguments in the proper position in that code, and then calls eval to work out the value of that code. The idea of a macro as something that writes a piece of text that has the form of code, and then runs (or evaluates) that code, is a general one in many languages.
arguments EVAL Body of function result Ordinary function calling arguments Body of macro result Lisp expression Calling a macro EVAL
Trying set-def without a macro (defun set-def (var val) (setf var val) ) Various things go wrong with this: > (set-def x 6) ERROR: Unbound variable – X We could try changing it slightly by using the function “boundp” which checks if its argument is currently bound to some value; (defun set-def (var val) (cond ( (boundp var) var) ( t (set var val)))) This line is intended to mean “if var is bound to some value, then return the value of var ” This is better, but it still won’t work, and for the same reason: if we try to call it with an unbound variable, we’ll get an error: the arguments to a function always must be bound to a value.
(defmacro set-def (var value) (list ‘cond (list(list ‘boundp (list ‘quote var)) var ) (list ‘t (list ‘setf var value) ) ) ) This macro uses quotes (‘) and the incoming variables to make up a lisp expression. After that expression is constructed, it is evaluated.
Set-def using a macro (defmacro set-def (var value) (list ‘cond (list (list ‘boundp (list ‘quote var)) var ) (list ‘t (list ‘setf var value) ) )) Suppose var=x and value=6. Then the line (list (list ‘boundp (list ‘quote var)) var ) will turn into ( (boundp ‘x) x) The line (list ‘t (list ‘setf var value) ) will turn into ( t (setf x 6) ) And the whole body of the macro will turn into (cond ( (boundp ‘x) x) (t setf x 6)) If we then evaluate (cond ( (boundp ‘x) x) (t setf x 6)), we will get the value of x (if x is bound) or we will setf x to 6 (otherwise)
Macros for checking input (defmacro set-def (var value) (cond((not (symbolp var)) (error “Non-symbol first argument to SET-DEF: ~s” var)) (t(list‘cond (list (list ‘boundp (list ‘quote var)) var) (list ‘t(list ‘setf var value)) ))) symbolp takes something and checks whether it has the syntactic form of a symbol (that is, whether it is suitable to be a variable name) Notice that we can use cond and all other components of our functions as normal inside a macro. In addition to using those expressions, we quote them in making up the expression that the macro evaluates to.
WRITING MACROS Write out a sample call of the macro you would like to have, using some illustrative arguments; Then, write out the slab of Lisp code you would like this sample call to be transformed into Decide what part of this sample text should be arguments, as they will vary for each use of the macro and give them symbolic names Lastly, try to write down that transformed form using quotes for the lisp expressions that are part of that code, and including the macro arguments.