Control in LISP More on Predicates & Conditionals
Equality Tests n LISP provides multiple equality tests –EQUAL and = –EQL and EQ n Serve different purposes –they give different answers in some cases
Equal and = n EQUAL is for general comparisons n = is used for numeric comparisons –an error to use = with non-numbers n = does type conversion; EQUAL does not –(= ) returns T –(equal ) returns NIL
Eq n EQ is “pointer” equality –are these “two” objects pointing to the same hunk of memory n T if same atom or same variable n Maybe T if same number & type > (list (eq ‘a ‘a) (eq ‘(a) ‘(a))) (T NIL)
Eq and SetF > (setf a ‘(1 2 3)) > (setf b ‘(1 2 3)) > (setf c a) > (list (eq a ‘(1 2 3)) (eq a a) (eq a b) (eq a c)) (NIL T NIL T) n A and B are different, but A and C are same –even tho’ they all look exactly the same
Eql and Eq n EQL is just like EQ except for numbers n A number is always EQL to itself –it may not be EQ to itself –neither EQ nor EQL if different types > (list (eql ) (eql ) (eq )) (T NIL T)or(T NIL NIL)
Equal n EQUAL is general purpose –except for numbers it’s what you’d expect > (setf a ‘(1 2 3)) > (setf b ‘(1 2 3)) > (list (equal a ‘(1 2 3)) (equal a a) (equal a b)) (T T T) > (list (equal 1 1.0) (equal a ‘( ))) (NIL NIL)
Equal is Equal n EQUAL goes all the way down –lists with lists treated properly > (equal ‘(1 (2 (3 4) (5 6))) ‘(1 (2 (3 4) (5 6)))) T > (equal ‘(1 2 (3 4)) ‘( )) NIL
Testing for Equality n Use EQUAL if need to compare lists n Use EQ or EQL for atoms/integers –more efficient than equal n Use = for general numbers –only one that equates integers with floats
Exercise n True, false, either or error: (eq ‘a ‘a) (eq 10 10) (eq ) (eq ‘(10) ‘(10.0)) (equal ) (equal ‘(10) ‘(10.0)) (eql ‘a ‘a) (eql 10 10) (eql ) (eql ‘(10) ‘(10.0)) (= ) (= ‘(10) ‘(10.0))
Data Type Predicates n Can test an object to see whether it’s a particular type –ATOM, NUMBERP, SYMBOLP, LISTP –(no P at the end of ATOM) n Numbers and symbols are also atoms n NIL is an atom and a list
Testing for Type > (list (atom ‘a) (numberp ‘a) (symbolp ‘a) (listp ‘a)) (T NIL T NIL) > (list (atom 5) (numberp 5) (symbolp 5) (listp 5)) (T T NIL NIL) > (list (atom ()) (numberp ()) (symbolp ()) (listp ())) (T NIL T T) > (list (atom ‘(a 1)) (numberp ‘(a 1)) (symbolp ‘(a 1)) (listp ‘(a 1))) (NIL NIL NIL T)
Exercise n Evaluate: > (setf a ‘(+ 2 5)) > (list (atom ‘a) (numberp ‘a)) > (list (atom a) (numberp a)) > (list (atom (+ 2 5)) (numberp (+ 2 5))) > (list (listp ‘a) (listp a) (listp (+ 2 5))) > (list (symbolp ‘a) (symbolp a) (symbolp (+ 2 5)))
Number Tests n Simple tests on numbers –ZEROP, PLUSP, MINUSP, EVENP, ODDP n All do what you’d expect, but –errors if not given numbers –errors if given more than one argument > (list (zerop 0) (plusp 1) (minusp 2) (evenp 3)) (T T NIL NIL)
Compound Conditions n LISP provides functions for logical combination of conditions –AND, OR, NOT n Can be used anywhere a condition is required
Logical And n All arguments must be true (i.e. non-NIL) –returns NIL if one argument is NIL –returns last argument if all non-NIL > (and (member ‘a ‘(d a d)) (member ‘o ‘(m o m))) (O M) > (and (member ‘a ‘(d a d)) (member ‘b ‘(m o m))) NIL
Exercise n Evaluate the following: > (and (member ‘a ‘(d a d)) (member ‘u ‘(b u d))) > (and (member ‘a ‘(d a d)) (atom ‘(b u d))) > (and (eq ‘a ‘a) (eql ‘a ‘a) (equal ‘a ‘a)) > (and (eql ) (= )) > (and (atom nil) (listp nil) (numberp nil)) > (and (numberp 10) (numberp 20) ( ))
Logical Or n One argument must be non-NIL –returns NIL if all are NIL –returns first non-NIL if one is non-NIL > (or (member ‘a ‘(d a d)) (member ‘b ‘(m o m))) (A D) > (or (member ‘a ‘(d u d)) (member ‘b ‘(m i m))) NIL
Exercise n Evaluate the following: > (or (member ‘a ‘(d a d)) (member ‘u ‘(b u d))) > (or (member ‘a ‘(b u d)) (atom ‘(b u d))) > (or (eq ‘a ‘a) (eql ‘a ‘a) (equal ‘a ‘a)) > (or (eql ) (= )) > (or (atom ‘a) (listp ‘a) (numberp ‘a)) > (or (numberp 10) (numberp 20) ( ))
Logical Not n Reverses its one argument –returns T if argument is NIL –returns NIL if argument is non-NIL > (not (member ‘a ‘(d a d))) NIL > (not (member ‘b ‘(m o m))) T
Exercise n Evaluate the following: > (not (member ‘a ‘(d a d))) > (not (member ‘u ‘(b a d))) > (not (or (member ‘a ‘(d a)) (member ‘u ‘(u p)))) > (not (and (member ‘a ‘(d a)) (member ‘u ‘(u p)))) > (or (not (atom ‘a)) (not (listp ‘a))) > (and (not (evenp 3)) (or (oddp 8) (zerop 0)))
Exercise n Write a function that takes an atom and two lists, and says how many of the lists the atom is in: ‘none, ‘one, or ‘both > (two-member ‘a ‘(s a d) ‘(d a d)) BOTH > (two-member ‘o ‘(c a l m) ‘(m o m)) ONE
“Short-Circuit” Evaluation n AND & OR are special forms –only evaluate arguments until answer known –can “guard” conditions > (defun eqn (M N) (and (numberp N) (numberp M) (= N M))) > (eqn ) T > (eqn ‘a ‘a) NIL
Short Circuits > (eqn ) (and (numberp 15) => T (numberp 15.0) => T (= ) => T ) => T > (eqn ‘a ‘a) (and (numberp ‘a) => NIL ) => NIL n Doesn’t do: (numberp ‘a) => NIL (= ‘a ‘a) => ERROR AND stops as soon as it sees a NIL
Short Circuits n OR stops as soon as it sees non-NIL (setf L ‘(a)) (or (null L) (= (length L) 1) (eq (first L) (second L)) (or (null ‘(a)) => NIL (= (length ‘(a)) 1) => (= 1 1) => T ) => T Does not compare (first L) = a with (second L) = NIL
Exercise n Write “safe” versions of EVENP & PLUSP –don’t give errors when called with non- numbers n Version 1: use if, when or unless n Version 2: use and, or or not
Case n CASE special form simplifies CONDs –all conditions (except else) involve checking one object against others > (defun fib (N) (cond ((= N 0) 1) ((= N 1) 1) (T (+ (fib (– N 1)) (fib (– N 2)))))) FIB
Case n CASE is a special form –first argument is evaluated –remaining arguments are not > (defun fib (N) (case N (01) (11) (T (+ (fib (– N 1)) (fib (– N 2))))))
Case Cases n Cases appear a (LABEL FORM) pairs n First matching case is selected –the form paired with it is evaluated & returned n Matching: –if LABEL is T or OTHERWISE, match –if LABEL is an atom, use EQL to compare –if LABEL is a list, use member on that list
Compound Case > (defun fib2 (N) (case N ((1 2)1) (T (+ (fib2 (– N 1)) (fib2 (– N 2)))))) n Calls (member N ‘(1 2)) for first case n Just succeeds for second case
Exercise n Write a function to expand three-letter abbreviations for days of the week to the full day name. Use a case statement. –return NIL if the day is not recognized > (day-full-name ‘wed) WEDNESDAY
Exercise n Write a function with case statement to return the number of days in a month (given as a 3-letter abbr.). Ignore leap years. –Thirty days hath September, April, June and November. All the rest have thirty-one, Save February all alone, Which hath twenty eight days clear, & so on
Next Time n More Control in LISP –Chapters 4, 5 & 7