Transcript

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta

1

CSCI 2210: Programming in Lisp

Procedures

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 2

Example: Our-third

Function to get the third element of a list> (third '(a b c d e))c

How can we do this without using THIRD?– Want to create our own function, OUR-THIRD that mimics THIRD

> (our-third '(a b c d e))c

– Definition of OUR-THIRD> (defun our-third (x) (first (rest (rest x))))OUR-THIRD

Many Lisp built-in functions can be written using other Lisp built-in functions See Appendix B, Lisp in Lisp.

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 3

Example: Both-ends

Define a procedure that gives both ends of a list> (setf itinerary ’(Albany NYC Chicago Seattle Anchorage))> (both-ends itinerary)

(ALBANY ANCHORAGE)

Three steps Get first element

> (first itinerary)ALBANY

Get last element> (first (last itinerary))

ANCHORAGE

Combine the two> (list (first itinerary) (first (last itinerary)))

Define procedure> (defun both-ends (l) (list (first l) (first (last l))))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 4

Example: Distance

Write a function to find the distance between 2 points.

> (defun sqr (x) (* x x))SQR

> (defun distance (x1 y1 x2 y2) (sqrt (+ (sqr (- x2 x1)) (sqr (- y2 y1)))))

DISTANCE> (setf originx 0 originy 0)

0> (distance originx originy 2 2)

1.414– Must have correct number of arguments– The value of each argument is copied to the corresponding parameter

originx copied to x1originy copied to y12 copied to x22 copied to y2

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 5

Scope Consider

> (setf a ’ORIG-A b ’ORIG-B c ’ORIG-C)ORIG-C

> (list a b c)(ORIG-A ORIG-B ORIG-C)

> (defun myfun (a) (setf a ’myfun-a) (setf b ’myfun-b) (list a b))

> (myfun c)(MYFUN-A MYFUN-B)

> (list a b c)(ORIG-A MYFUN-B ORIG-C)

Value of C is copied to A– Parameter passing: Pass by Value (Like C/C++ default)

Global variables are still accessible!– Like C/C++ Global variables

Lexical variable: variable declared as a parameter Special variable: variable not declared as a parameter

A,B,C A

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 6

Let

Let = Lisp’s way of defining local variables(let ( (<var1> <value1>) (<var2> <value2>) … ) <expr1> <expr2>)

Example(defun distance (x1 y1 x2 y2) (let ( (dx (- x2 x1)) (dy (- y2 y1)) ) (sqrt (+ (sqr dx) (sqr dy))) ))

Let evaluates in parallel (not sequentially) Uses original values of variables in all (<var> <value>) pairs

(let ( (dx (- x2 x1)) (dy (- y2 y1)) (dx_sqr (sqr dx)) (dy_sqr (sqr dy)) ) ;;

Won’t work! (sqrt (+ dx_sqr dy_sqr)) )

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 7

Let vs. Let*

Let - Parallel evaluation> (setf x ’outside)

OUTSIDE> (let ((x ’inside) (y x)) (list x y))

(INSIDE OUTSIDE)

Let* - Sequential evaluation> (setf x ’outside)

OUTSIDE> (let* ((x ’inside) (y x)) (list x y))

(INSIDE INSIDE)

Let* Implementation of distance(let* ( (dx (- x2 x1)) (dy (- y2 y1)) (dx_sqr (sqr dx)) (dy_sqr (sqr dy)) ) ;;

OK! (sqrt (+ dx_sqr dy_sqr)) )

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 8

Exercise

1. Rewrite the distance function to use “setf” instead of “let”. Explain the difference.

2. Write the function solve-quadratic such that, given a,b,c, the function finds all values of x for which ax^2 + bx + c = 0.

x1 = (-b + sqrt (b^2 - 4ac)) / 2ax2 = (-b - sqrt (b^2 - 4ac)) / 2a

The function should return both values of x as a list of two elements. For example,

> (solve-quadratic 1 -2 1)(1.0 1.0)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 9

Example: Solve-quadratic

Solution to solve-quadratic(defun solve-quadratic (a b c) (let ((sqrt_clause (- (* b b) (* 4 a c))) (neg_b (- b)) (two_a (* 2 a)) ) (list (/ (+ neg_b (sqrt sqrt_clause)) two_a) (/ (- neg_b (sqrt sqrt_clause)) two_a))))

Notes - No error checking is done (- (* b b) (* 4 a c)) might result in a negative number

– What happens when you try to take sqrt of a negative number?

What happens when the value of A is zero?

Need Predicates - to determine when error conditions occur (e.g. =) Conditionals - to do something else when error occurs

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 10

EQUAL does not = EQL

Several predicates check equality Slightly different semantics

– Can be confusing

Equality predicates Equal - Are two argument values the same expression? Eql - Are two argument values the same symbol or number? Eq - Are two argument values the same symbol? = - Are two argument values the same number?

General Rule of Thumb Use = when you want to compare numbers Use EQUAL otherwise

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 11

Relationships Bet Equality Pred’s

EQ vs. = = returns T if two numbers are the same, regardless of their type EQ returns T if two arguments are the same symbol

– Same chunk of memory– Identical primitives sometimes are EQ

Examples> (eq 4 4) ;; EQ:T =:T (C)> (eq (/ 1 4) 0.25) ;; EQ:NIL =:T (A)> (eq ’A ’A) ;; EQ:T =:Error (D)> (eq 4.0 4.0);; EQ:NIL =:T (A)

= EQ EQL EQUAL

A

B C

D

F

E

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 12

EQL vs. =

EQL Arguments are EQL if they are either EQ or they are equivalent

numbers of the same type Examples

> (eq 4.0 4.0) ;; EQ:NIL EQL:T =:T (B)> (eq 4 4.0) ;; EQ:NIL EQL:NIL =:T (A)

EQUAL Arguments are EQUAL if they are either EQL or they are Lists

whose elements are EQUAL Performs an element by element comparison of lists

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 13

EQUAL vs. EQL vs. =

EQUAL vs. EQL> (setf X ’(A (B (C))))> (setf Y X)> (setf Z ’(A (B (C))))

X and Y are EQUAL and EQL X and Z are EQUAL but not EQL

– They don’t point to the SAME memory– But, if you do an element by element

comparison of the lists, they are equal

EQUAL vs. => (EQUAL 4 4.0)

NIL> (= 4 4.0)

T

B

C

A

Z

B

C

A

X

Y

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 14

Data Type Predicates

Data Type Predicates Compare objects to determine their type

– atom - Is argument an atom?– numberp - Is argument a number?– symbolp - Is argument a symbol (a non-numeric atom)?– listp - Is argument a list?

Examples> (list pi ’ABC)

(3.14159 ABC)> (list (atom pi) (atom ’ABC))

(T T)> (list (numberp pi) (numberp ’ABC))

(T NIL)> (list (symbolp pi) (symbolp ’ABC))

(NIL T)> (list (listp pi) (listp ’ABC) (listp ’(A B))

(NIL NIL T)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 15

Number Predicates

Number predicates numberp - Is it a number? zerop - Is it zero? Argument must be a number plusp - Is it positive? Argument must be a number minusp - Is it negative? Argument must be a number evenp - Is it even? oddp - Is it odd? > - Is the list of arguments in descending order? (e.g. (> 5 4)) < - Is the list of arguments in ascending order?

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 16

If, When, Unless

If (if <test> <then-form> <else-form>) if <test> is true

– <then-form> is evaluated, – otherwise <else-form> is evaluated.

When (when <test> <then-form1> <then-form2> …) If <test> is true, then other arguments are evaluated.

Unless (unless <test> <else-form1> <else-form2> …) If <test> is false, then other arguments are evaluated.

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 17

Cond

Cond format(COND (<test1> <then-1-1> <then-1-2> …) (<test2> <then-2-1> <then-2-2> …) (<test3> <then-3-1> <then-3-2> …) … (<testi> <then-i-1> <then-i-2> …) … (<testm> <then-m-1> <then-m-2> …)

Semantics 1. Evaluate <test1>, <test2>, … until you get to a <testi> such

that <testi> evaluates to a nonNIL value 2. Evaluate <then-i-1> <then-i-2> … 3. Return value of the last <then-i-n> clause executed

If all tests evaluate to NIL, result of COND is NIL

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 18

Example

Define a function to find area(defun area (type r) (cond ((equal type ’circle) (* PI R R)) ((equal type ’sphere) (* 4 PI R R)) ((equal type ’square) (* R R) ((equal type ’cube) (* 6 R R)) ( t (print “Error”) ))

Define a function, compute-grade, to determine the letter grade.

(compute-grade 81.5)B

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 19

Case

Similar to COND, but is more elegant when checking for equality

(defun area (type r) (case type (circle (* PI R R)) (sphere (* 4 PI R R)) (square (* R R) (cube (* 6 R R)) (otherwise (print “Error”) ))

Format(case <key-form> (<key 1> <then-1-1> <then-1-2> …) (<key 2> <then-2-1> <then-2-2> …) … (<key m> <then-m-1> <then-m-2> …) (otherwise <then-o-1> <then-o-2> …)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 20

Case (2)

Notes <key-form> is evaluated

– But, <key 1> <key 2>, … are NOT evaluated

“OTHERWISE” or “T” always evaluate to nonNIL If no matches are found, the CASE statement returns NIL A <key> form may contain a list. In this case, the <key-form>

can match ANY element of the list(defun circularp (type) (case type ((circle sphere) ’T) (otherwise NIL)))(circularp ’cube)

– Technical note: the MEMBER function is used to do the comparison.

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 21

Both-ends Revisited

Both-ends with error handling(defun both-ends (l) (if (listp l) (case (length l) (0 NIL) (1 (list (first l) (first l))) (t (list (first l) (first (last l))))) NIL))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 22

Solve-quadratic revisited

Solve-quadratic with error checking Checks for errors; returns NIL instead

(defun solve-quadratic (a b c) (if (not (and (numberp a) (numberp b) (numberp c))) NIL ; at least one argument is not a number (let ((sqrt_clause (- (* b b) (* 4 a c))) (neg_b (- b)) (two_a (* 2 a)) ) (cond ((minusp sqrt_clause) NIL) ((= 0 a) NIL) ; Could have used zerop (t (list (/ (+ neg_b (sqrt sqrt_clause)) two_a) (/ (- neg_b (sqrt sqrt_clause)) two_a)))))))

What happens if we don't include the clause(minusp sqrt_clause) …

– By default, Lisp arithmetic operations handle complex numbers

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 23

Factorial Definition of Factorial C++ Implementation

int factorial (int x) { int i,f; f = 1; for (i=1; i<=x; i++) f = f * i; return f;}

Lisp Implementation(defun factorial (n) (let ((f 1)) (dotimes (i n f) (setf f (* f (+ i 1))))))

– Note: To more easily compare, C++ loop could have been written as:for (i=0; i<x; i++) f = f * (i + 1);

Tip: Compute factorial(100) using C/C++ and Lisp

)1(

*...*3*2*1

1

0

1

i

Ni

N

i

N

i

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 24

DoTimes

DOTIMES is Lisp’s way of doing iteration C/C++

for (i=0; i<n; i++) { <body>}

Lisp (dotimes (i n) <body>)

First parameter is a list with three elements– counter variable (e.g. i)– number of times to iterate (e.g. n)

Counter variable (i) ranges from 0 to n-1 Optional return value can be specified (default is NIL)

(dotimes (i n return_value) <body>)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 25

Recursively Calculating Factorial Mathematical Definition of Factorial

C/C++ Implementationlong Factorial (long X) { if (X <= 1)

return 1; else

return X * Factorial(X-1);}

Lisp Implementation(defun recursive-factorial (x) (if (<= x 1) 1 (* x (recursive-factorial (- x 1)))))

XX

X X X!

, ;

*( )!,

1 1

1 1

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 26

Recursive calls Show recursion when calling (recursive-factorial 4)

Begin (recursive-factorial 4) Since 4>1, evaluate 4 * (recursive-factorial 3) Begin (recursive-factorial 3) Since 3>1, evaluate 3 * (recursive-

factorial 2) Begin (recursive-factorial 2) Since 2>1, evaluate 2*(recursive-

factorial 1) Begin (recursive-factorial 1) Since 1<=1, return 1 End (recursive-factorial 1),

returns 1 2 * (recursive-factorial 1) = 2 * 1

= 2 End (recursive-factorial 2), returns 2 3 * (recursive-factorial 2) = 3 * 2 = 6 End (recursive-factorial 3), returns 6 4 * (recursive-factorial 3) = 4 * 6 = 24End (recursive-factorial 4), returns 24

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 27

MEMBER

MEMBER Checks if first argument is an element of second argument Returns what is left of the list when symbol is found

> (setf sentence ’(tell me more about your mother please))

(TELL ME MORE ABOUT YOUR MOTHER PLEASE)> (member ’mother sentence)

(MOTHER PLEASE)

Only checks the top level for a match (using EQL)> (member ’mother ’((father son) (mother

daughter)))NIL

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 28

Example: Our-member

Our-Member(defun our-member (obj aList) (if (null aList) nil (if (eql (first aList) obj) aList (our-member obj (rest aList)))))

This "design pattern" is used frequently in Lisp for recursive methods that operate on Lists

(defun <recursive-function (aList) (if <base condition> <terminate with return value> <process first element> <recursively process everything except the first element>))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 29

MEMBER; Keyword Modifiers

MEMBER tests for membership using EQL> (setf pairs ’((maple shade) (apple fruit)))> (first pairs)

(MAPLE SHADE)> (member (first pairs) pairs)

((MAPLE SHADE) (APPLE FRUIT))> (member ’(maple shade) pairs)

NIL

Use keyword modifier to override> (member ’(maple shade) pairs :test #’equal)

((MAPLE SHADE) (APPLE FRUIT))

:test is a keyword; it expects an argument of type procedure #’equal is a keyword argument

– #’ is a macro– #’equal expands to (function equal)– Returns the procedure object named “equal”

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 30

Keywords; Procedure Macro

Why use keywords? Why not just an optional parameter?

> (member ’(maple shade) pairs #’equal)

Keywords allow more than one type of behavior modification– :test-not is another keyword for MEMBER

Why use procedure objects? Why not just allow procedure name to be passed?

> (member ’(maple shade) pairs :test equal)

Procedure objects can be bound to variable names> (setf predicate #’equal)> (member ’(maple shade) pairs :test predicate)

Can pass them as parameters to functions, etc.

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 31

Recursive Definition of Length

Length(defun mylength (l) (if (endp l) 0 (+ 1 (mylength (rest l)))))

Alternate definition(defun mylength2 (l) (mylength2-aux l 0))(defun mylength2-aux (l count) (if (endp l) count (mylength2-aux l (+ count 1))))

Note All recursive calls simply return the final value evaluated. No additional computations

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 32

Tail Recursion

Tail Recursion The final expression of a function is a recursive call No additional computations are done to that expression

– That is, return value is JUST the result of the recursive call

Lisp handles tail recursion efficiently Mylength is not tail recursive Mylength2 is tail recursive

Example: Write a function to produce N atoms with value ‘A’.

> (produce-list-of-a 5) ; Example call(A A A A A)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 33

Produce-list-of-a Using dotimes

(defun produce-list-of-a (n) (let ((la NIL)) (dotimes (i n la) (push 'A la))))

Recursion, not tail recursive(defun produce-list-of-a (n) (if (= n 0) nil (cons 'A (produce-list-of-a (- n 1)))))

Recursion, with tail recursion(defun produce-list-of-a (n) (produce-list-of-a-aux n NIL))(defun produce-list-of-a-aux (n list-so-far) (if (= n 0) list-so-far (produce-list-of-a-aux (- n 1) (cons 'A list-so-far))))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 34

Tower of Hanoi

Three pegs, S(start), T(temp), E(end) N disks Goal: Move disks from peg S to peg E Restriction: Larger disk can’t be placed on top of

smaller disk

S T E

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 35

Tower of Hanoi

Solution to Tower of Hanoi(defun hanoi-aux (n start end temp) (if (> n 1) (hanoi-aux (- n 1) start temp

end)) (print (list start end)) (if (> n 1) (hanoi-aux (- n 1) temp end

start)))(defun hanoi (n) (hanoi-aux n 'S 'E 'T))

Example Runs> (hanoi 2)

(S T) (S E) (T E) NIL

> (hanoi 3)(S E) (S T) (E T) (S E) (T S) (T E) (S E) NIL

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 36

&Optional

Produce-list-of-a function(s)(defun produce-list-of-a (n) (produce-list-of-a-aux n NIL))(defun produce-list-of-a-aux (n list-so-far) (if (= n 0) list-so-far (produce-list-of-a-aux (- n 1) (cons 'A list-so-far))))

Redefined with optional parameters(defun produce-list-of-a (n &optional list-so-far) (if (= n 0) list-so-far (produce-list-of-a (- n 1) (cons 'A list-so-far))))

Note: optional values are bound to NIL, by default

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 37

Optional Parameters (cont)

Solution to Hanoi(defun hanoi-aux (n start end temp) (if (> n 1) (hanoi-aux (- n 1) start temp

end)) (print (list start end)) (if (> n 1) (hanoi-aux (- n 1) temp end

start)))(defun hanoi (n) (hanoi-aux n 'S 'E 'T))

Revised with optional parameters(defun hanoi (n &optional (start 'S) (end 'E)

(temp 'T)) (if (> n 1) (hanoi (- n 1) start temp end)) (print (list start end)) (if (> n 1) (hanoi (- n 1) temp end start)))

Note: notice the syntax for initializing optional parameters

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 38

&Rest

&Rest - Specifies a variable number of arguments Example: Assume + only accepts 2 arguments. Define “Plus”,

a function that adds an arbitrary number of arguments)> (plus 2 3)> (plus 2 3 4 5 8)

Solution(defun plus (arg1 &rest other_args) (plus-aux arg1 other_args))(defun plus-aux (arg1 other_args) (if (null other_args) arg1 (plus-aux (+ arg1 (first other_args)) (rest other_args))))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 39

Key Parameters

KEYword parameter Useful when function has MANY parameters Most are tied to default values

Examples> (rotate-list '(a b c d e)) ; rotate one element

right(E A B C D)

> (rotate-list '(a b c d e) :direction 'left)(B C D E A)

> (rotate-list '(a b c d e) :distance 2)(D E A B C)

> (rotate-list '(a b c d e) :direction 'left :distance 2)

(C D E A B)

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 40

&Key

Use &key to define Key parameters(defun rotate-list (l &key (direction 'right)

(distance 1)) (if (eq direction 'left) (rotate-list-left l distance) (rotate-list-right l distance)))

(defun rotate-list-right (l n) (if (zerop n) l (rotate-list-right (append (last l)

(butlast l)) (- n 1))))(defun rotate-list-left (l n) (if (zerop n) l (rotate-list-right (append (rest l) (list

(first l))) (- n 1))))

CSCI 2210 - Programming in Lisp; Instructor: Alok Mehta 41

&Aux

&Aux keyword is used as a shorthand for Let* Produce-list-of-a using Let*

(defun produce-list-of-a (n) (let* ((la NIL)) (dotimes (i n la) (push 'A la))))

Using &Aux(defun produce-list-of-a (n &aux (la NIL)) (dotimes (i n la) (push 'A la)))


Recommended