# Functional Programming COMP2003 - PowerPoint PPT Presentation

1 / 18

Functional Programming COMP2003. A course on functional programming using Common Lisp Dr Eleni Mangina eleni.mangina@ucd.ie. Macros and evaluation. A macro is a way of making a Lisp expression behave as if it were a different, but related, Lisp expression.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

Functional Programming COMP2003

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

## Functional Programming COMP2003

A course on functional programming using Common Lisp

Dr Eleni Mangina

eleni.mangina@ucd.ie

### Macros and evaluation

• A macro is a way of making a Lisp expression behave as if it were a different, but related, Lisp expression.

• A macro is a user-definable Lisp procedure which operates by rearranging its arguments into the form of piece of Lisp text, and letting the system 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

• The main use of macros is to make some piece of Lisp program behave like some other, systematically related, piece of program – textual re-arrangement is the central idea.

arguments

arguments

Body of function

EVAL

S-expression

Body of function

EVAL

result

result

Ordinary function calling

Calling a macro

Example

Suppose we are writing a program in which we often with to carry out a computation which could be roughly summarized as follows:

“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”

It would be helpful if we could define ourselves a single command SET-DEF which does this:

> (set-def x 6)

6

> x

6

> (set-def x 12)

6

> x

6

SET-DEF could then be used whenever we need this computation. Attempting to define SET-DEF as a simple DEFUN function would be difficult, since such a function would try to evaluate all its arguments and hence would evaluate the variable name which we are trying to alter.

(defun set-def (nm val)

;; This won’t work correctly

(setf nm 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 value; there is also a construct “set”which evaluates its first argument and if the value found is a symbol, it assigns its second argument to that variable. SO:

(defun set-def (nm val)

;; this won’t work either

(cond ((boundp nm) nm)

(t (set nm val))))

(defmacro set-def (var value)

(list ‘cond

(list(list ‘boundp

(list ‘quote var))

var

)

(list ‘t (list ‘setf var value)

)

)

)

(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 (lis ‘quote var))

var

)

(list ‘t(list ‘setf var value))

)

)

)

)

### Things to note about macros

• Argument evaluation: The arguments passed to a macro are not evaluated as in a normal function, so if a macro were passed a parenthesized expression as one of its parameter-values, say (rest (first l)) then inside the body of the macro, the parameter would have as its value the list which looks like this – its first element would be the symbol rest, and its second element would be a list (first l) with first element first and second element l. The computation extracting the rest of the first of l would not yet have occurred.

• Result evaluation: Once the macro body has constructed its result, which should be in the form of a bit of program text, that expression gets EVALuated outside the macro, in the environment where the macro was originally called

>(setf var nil)

nil

>(set-def var (first list3))

This call of the macro will create the result expression:

(cond ((boundp ‘var) var)

(t(setf var (first list3)))

)

>(setf x 3)

3

>(defun test (x)

(eval ‘x))

TEST

>(test 5)

3

>(defmacro mac-1 ()

(list ‘print ‘x))

MAC-1

> (defun t1 (x)

(mac-1))

T1

> (t1 7)

7

7

### MACROEXPAND

• This is a very handy built-in function for helping you to debug your macro definitions. The function MACROEXPAND takes any Lisp item as its argument and goes through it “expanding” any macros it finds.

> (macroexpand ‘(set-def m nil))

(cond ((bound ‘m) m) (t (setf m nil)))

t

### 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 back quote, comma and comma-at to provide the link to the arguments

Hence, a macro might look something like:

(defmacro example-mac (arg1 arg2)

(cond ((args-invalid arg1 arg2) (error “…”))

(t (create-result (arrange-args arg1 arg2)))

)

)

### EXERCISE

• Define and test a macro of no arguments called cheer which expands to an expression which will print out the string “HOORAY HOORAY”. Try using MACROEXPAND on your defined macro and see what results you get

### EXERCISE

• Define and test a macro of one argument called lastitem which expands to an expression which will return the last element in the value of its argument assuming that the argument evaluates to a list. For example:

> (lastitem ‘(a b c d))

d

> (lastitem (first (rest (‘(a (b c) d))))

c

The result should not be a “list containing the last element”- it should be the element itself

### EXERCISE

• Write a macro which implements a conditional IF-THEN-ELSE statement. This macro (call it IFF) should allow two possible styles of call:

(IFF <test> THEN <action>)

(IFF <test> THEN <action-1> ELSE <action-2>)

where each test is a single S-expression and so is action. For example:

(iff (eql x y) then (return sum))

(iff (atom s) then 1

else (+ (count (first s)) (count (rest s))))

The meaning of these calls is as follows. If the <test> yields a non-nil result when evaluated, the <action> following the THEN symbol is evaluated and the result of that returned as the overall result; if the <test> yields false, and there is no ELSE <action> given, NIL is returned from the IFF statement; if the <test> yields false, and there is an ELSE <action-2> given, that <action-2> is evaluated, and the result of that is returned from the IFF statement.

### EXERCISE

• Write a macro WHILE which allows an iterative command. The usage permitted is to be:

(while <test>

do<expression-1>

<expression-N>

)

where the <test> and each <expression> is a single S-expression. For example

(while (< n 100)

do

(print (sqrt n))

(setf n (1+ n))

)

The meaning of this is as follows. The sequence of <expression> is to be evaluated repeatedly until the <test> yields NIL when evaluated. The test is evaluated before each pass over the <expressions>, so if it starts off being NIL, no evaluation of the body of the loop occurs. If the ordinary Lisp RETURN construct is evaluated inside the body of the WHILE loop then the loop should terminate in the normal Lisp way, with the argument to RETURN being passed back as the result; if this does not happen the overall result of evalluating the WHILE construct should be NIL.

### EXERCISE(Working on more complicated projects)

The class of logical expressions correspond to atomic formulae in first order logic, such as:

p(a,b)

q(a, _x, g(a,c))

s(_x, f(_x,g(_y,a)), d)

Each complete formula consists of a predicate together with a sequence of one or more arguments. Each argument must be a term, which is either a constant, a variable, or a function term. Constants and variables are referred to as atomic terms. Variables are represented as symbols starting with underscores, constants as ordinary symbols. A function term consists of a function name followed by a sequence of one or more arguments, each of which must be a term.

Functions provided:

### EXERCISE (cont.)(Working on more complicated projects)

In this program a (LISP) function called MATCH needs to be implemented, which compares two (atomic) formulae for similarity, taking special account of variables in one of the terms. If the two arguments do not match, it returns NIL, if they match, in the sense that they can be made identical by replacing each logical variable with some (single) term, then a list is being returned containing exactly one element, a “table”in which the keys are the variables and the associated values are those which would make the original arguments identical. The first argument to MATCH may or may not contain logical variables, but an error is indicated if the second argument to MATCH contains logical variables. Both arguments to MATCH must be atomic logical formulae in the sense defined above. An error is indicated if either is not. The result returned is either NIL, if no match is possible, or a list of exactly one element otherwise. That element can be an empty table (if the match involved no variables) or a table of variables and values. A variable cannot be bound to two different values - the program checks this, and the match fails.

Examples:

(setf p1 (make-formula 'p (list 'x 'x '_Y)))

(setf p2 (make-formula 'p (list 'x 'x '())))

;>>(match p1 p2)

;((_Y NIL))

(setf p3 (make-formula 'p (list '())))

(setf p4 (make-formula 'p (list '())))

;>>(match p3 p4)

;(NIL)

(setf p5 (make-formula 'p (list 'x 'y 'z '() 'a (make-function-term 'f (list 'a 'b 'c)) 'a)))

(setf p6 (make-formula 'p (list 'x 'y 'z '() 'a (make-function-term 'f (list 'a 'b 'c)) 'a)))

;>>(match p5 p6)

;(NIL)

(setf p7 (make-formula 'p (list 'x 'x 'Y)))

(setf p8 (make-formula 'p (list 'x 'y '())))

;>>(match p7 p8)

;NIL

(setf p9 (make-formula 'p (list '_x 'y 'a '_w)))

(setf p10 (make-formula 'p (list 'x 'y 'a 'f)))

;>>(match p9 p10)

;((_X X _W F))

(setf p11 (make-formula 'p (list '_x '_y '_z '_w)))

(setf p12 (make-formula 'p (list 'x (make-function-term 'f (list 'a 'b 'c)) 'z 'w)))

;>>(match p11 p12)

;((_X X _Y (F A B C) _Z Z _W W))