COMMON LISP A GENTLE INTRODUCTION TO SYMBOLIC COMPUTATION
COMMON LISP: A GENTLE INTRODUCTION TO SYMBOLIC COMPUTATION 1 David S. Touretzky
INTRODUCTION 2
THE EVAL FUNCTION The EVAL function is the heart of Lisp. EVAL's job is to evaluate Lisp expressions to compute their result. Some example EVAL function: (+ 1 6) 7 (oddp (+ 1 6)) T (evenp (+ 1 6)) NIL (* 3 (+ 1 6)) 21 (/ (* 2 11) (+ 1 6)) 22/7 (/ (* 2 11) (+ 1 6. 0)) 3. 142857 (not (equal 5 6)) T ODDP : returns T if the input number is odd EVENP: returns T if the input number is even 3
EXERCISES What does (NOT (EQUAL 3 (ABS -3))) evaluate to? Write an expression in EVAL notation to add 8 to 12 and divide the result by 2. 4
DEFINING FUNCTIONS IN EVAL NOTATION The AVERAGE function is defined in EVAL notation this way: (defun average (x y) (/ (+ x y) 2. 0)) Another example of function definition with DEFUN: (defun square (n) (* n n)) A function that computed the total cost of a merchandise order might name its arguments QUANTITY, PRICE, and HANDLING-CHARGE. (defun total-cost (quantity price handling-charge) (+ (* quantity price) handling-charge)) 5
EXERCISES Define a function PYTHAG that takes two inputs, x and y, and returns the square root of x 2+y 2. You may recognize this as Pythagoras‘s formula (畢氏定理) for computing the length of the hypotenuse of a right triangle given the lengths of the other two sides. (PYTHAG 3 4) should return 5. 0. 6
USING SYMBOLS AND LISTS AS DATA In EVAL notation symbols are used to name variables, so if we write (equal kirk spock) Lisp will think we are trying to compare the value of the global variable named KIRK with the value of the global variable named SPOCK. Since we haven't given any values to these variables, this will cause an error: (equal kirk spock) Error! variable KIRK has no value. We can tell Lisp to treat KIRK and SPOCK as data rather than as variable references by putting a quote before each one. (equal 'kirk 'spock) nil Because the symbols T and NIL evaluate to themselves, they don't need to be quoted to use them as data. (list 'james t 'kirk) (james t kirk) 7
USING SYMBOLS AND LISTS AS DATA For examples: (defun riddle (x y) (list 'why 'is 'a x 'like 'a y)) (riddle 'raven 'writing-desk) (why is a raven like a writing-desk) PS: riddle 謎語 Lists also need to be quoted to use them as data; otherwise Lisp will try to evaluate them, which typically results in an ''undefined function'' error. (first (we hold these truths)) Error! undefined function WE. (first '(we hold these truths)) we (third (my aunt mary)) Error! undefined function MY. (third '(my aunt mary)) mary (+ 1 2) 3 '(+ 1 2) 8
THE PROBLEM OF MISQUOTING Some examples: (list 'a 'b c) Error! C unassigned variable. (list 'a 'b 'c) (a b c) (cons 'a (b c)) Error! B undefined function. ; cons: constitute (cons 'a '(b c)) (a b c) (+ 10 '(- 5 2)) Error! Wrong type input to +. (+ 10 (- 5 2)) 13 (list 'buy '(* 27 34) 'bagels) (buy (* 27 34) bagels) (list 'buy (* 27 34) 'bagels) (buy 918 bagels) ('foo 'bar 'baz) Error! 'FOO undefined function. '(foo bar baz) 10
THREE WAYS TO MAKE LISTS We have three ways to make lists using EVAL notation. (1) '(foo bar baz) (2) (list 'foo 'bar 'baz) (foo bar baz) (3) (cons 'foo '(bar baz)) (foo bar baz) Compare the following examples: (list 33 'squared 'is (* 33 33)) (33 squared is 1089) (list 33 'squared 'is '(* 33 33)) (33 squared is (* 33 33)) '(33 squared is (* 33 33)) (list foo bar baz) Error! FOO unassigned variable. (foo bar baz) Error! FOO undefined function. ('foo 'bar 'baz) Error! 'FOO undefined function. 11
EXERCISES Write down the results of the following expressions. (cons 5 (list 6 7)) (cons 5 '(list 6 7)) (list 3 'from 9 'gives (- 9 3)) (+ (length '(1 foo 2 moo)) (third '(1 foo 2 moo))) (rest '(cons is short for construct)) Study this function definition: (defun call-up (caller callee) (list 'hello callee 'this 'is caller 'calling)) How many arguments does this function require? What are the names of the arguments? What is the result of (CALL-UP 'FRED 'WANDA)? 12
FOUR WAYS TO MISDEFINE A FUNCTION An example: (defun intro (x y) (list x 'this 'is y)) (intro 'stanley 'livingstone) (stanley this is livingstone) Four ways to misdefine a function: The first way to misdefine a function is to put something other than plain (清楚的), unadorned(樸素的) symbols in the function's argument list. (defun intro ('x 'y) ; bad argument list (list x 'this 'is y)) (defun intro ((x) (y)) ; bad argument list (list x 'this 'is y)) 13 The second way to misdefine a function is to put parentheses around variables where they appear in the body.
FOUR WAYS TO MISDEFINE A FUNCTION The second way to misdefine a function is to put parentheses around variables where they appear in the body. (defun intro (x y) (list (x) 'this 'is (y))) (intro 'stanley 'livingstone) Error! X undefined function. The third way to misdefine a function is to quote a variable. Symbols must be left unquoted when they refer to variables. (defun intro (x y) (list 'x 'this 'y)) (intro 'stanley 'livingstone) (x this is y) The fourth way to misdefine a function is to not quote something that should be quoted. In the INTRO function, the symbols X and Y are variables but THIS and IS are not. (defun intro (x y) (list x this is y)) (intro 'stanley 'livingstone) Error! THIS unassigned variable. 14
MORE ABOUT VARIABLES Consider the DOUBLE function, which creates a variable named N every time we call it: (defun double (n) (* n 2)) Now let‘s try an example with two variables. Here is a definition for QUADRUPLE(四 倍數) in terms of DOUBLE: (defun quadruple (n) (double n))) Evaluate the expression (quadruple 5) 15
EXERCISES Consider the following function, paying close attention to the quotes: (defun scrabble (word) (list word 'is 'a 'word)) The symbol WORD is used two different ways in this function. What are they? What is the result of (SCRABBLE 'AARDVARK)? What is the result of (SCRABBLE 'WORD)? PS: scrabble英文拼字遊戲 Here's a real confuser: (defun stooge (larry moe curly) (list larry (list 'moe curly) curly 'larry)) What does the following evaluate to? It will help to write down what value each variable is bound to and, of course, mind the quotes! (stooge 'moe 'curly 'larry) PS: stooge喜劇裡的配角 16
LIST EXAMPLE An example: (defun long-function (some-list) (cons (third some-list) (list (second some-list) (fourth some-list) (first some-list)))) Break 4 [8]> (long-function '( a b c d)) (C B D A) Break 4 [8]> (long-function '( a b c d e f)) (C B D A) 17
EXERCISES Here is an example of the function MYFUN, a strange function of two inputs. (myfun 'alpha 'beta) ((ALPHA) BETA) Write MYFUN. Test your function to make certain it works correctly. What is wrong with this function? What does (FOO 5) do? (defun foo (x) (+ 1 (zerop x))) 18
FUNCTIONS OF NO ARGUMENTS Suppose we wanted to write a function that multiplies 85 by 97. Notice that this function requires no inputs. Since the function doesn't take any inputs, it will have an empty argument list. The empty list, of course, is NIL. Let's define this function under the name TEST: (defun test () (* 85 97)) After doing this, we see that (test) 8245 (test 1) Error! Too many arguments. 19
THE QUOTE SPECIAL FUNCTION QUOTE is a special function: its input does not get evaluated. The QUOTE special function simply returns its input. For example: (quote foo) foo (quote (hello world)) (hello world) (cons 'up '(down sideways)) is equal to (cons (quote up) (quote (down sideways))) The first quote is stripped away by the evaluation process, but any extra quotes remain. 'foo ''foo also written (quote foo) (list 'quote 'foo) (quote foo) also written 'foo (first ''foo) quote (rest ''foo) (foo) (length ''foo) 2 20
EVAL AND APPLY EVAL is a Lisp primitive function. Each use of EVAL gives one level of evaluation. '(+ 2 2) (eval '(+ 2 2)) 4 '''boing (eval '''boing) 'boing (eval '''boing) boing (eval '''boing))) Error! BOING unassigned variable. '(list '* 9 6)) (list '* 9 6) (eval '(list '* 9 6)) (* 9 6) (eval '(list '* 9 6))) 54 21
EVAL AND APPLY is also a Lisp primitive function. APPLY takes a function and a list of objects as input. It invokes (造成) the specified function with those objects as its inputs. The first argument to APPLY should be quoted with #' rather than an ordinary quote; #' is the proper way to quote functions supplied as inputs to other functions. (apply #'+ '(2 3 4 5)) 14 (apply #'/ '(2 3 4 5)) 1/30 (apply #'equal '(12 17)) nil The objects APPLY passes to the function are not evaluated first. In the following example, the objects are a symbol and a list. Evaluating either the symbol AS or the list (YOU LIKE IT) would cause an error. 22 (apply #'cons '(as (you like it))) (as you like it)
EXERCISES What do each of the following expressions evaluate to? (list 'cons t nil) (eval (list 'cons t nil))) (apply #'cons '(t nil)) (eval nil) (list 'eval nil) (eval (list 'eval nil)) 23
THE IF SPECIAL FUNCTION IF is the simplest Lisp conditional. Conditionals are always macros or special functions, so their arguments do not get evaluated automatically. The IF special function takes three arguments: a test, a true-part, and a false-part. If the test is true, IF returns the value of the true-part. If the test is false, it skips the true-part and instead returns the value of the false-part. Here are some examples. (if (oddp 1) 'odd 'even) odd (if (oddp 2) 'odd 'even) even (if t 'test-was-true 'test-was-false) test-was-true (if nil 'test-was-true 'test-was-false) test-was-false (if (symbolp 'foo) (* 5 5) (+ 5 5)) 25 (if (symbolp 1) (* 5 5) (+ 5 5)) 10 24
THE IF SPECIAL FUNCTION Use IF to construct a function that takes the absolute value of a number. (defun my-abs (x) (if (< x 0) (- x) x)) > (my-abs -5) 5 > (my-abs 5) unchanged. 5 ; True-part takes the negation. ; False-part returns the number 25
THE IF SPECIAL FUNCTION Here's another simple decision-making function. SYMBOL-TEST returns a message telling whether or not its input is a symbol. (defun symbol-test (x) (if (symbolp x) (list 'yes x 'is 'a 'symbol) (list 'no x 'is 'not 'a 'symbol))) > (symbol-test 'rutabaga) ; Evaluate true-part. (YES RUTABAGA IS A SYMBOL) > (symbol-test 12345) ; Evaluate false-part. (NO 12345 IS NOT A SYMBOL) IF can be given two inputs instead of three, in which case it behaves as if its third input (the false-part) were the symbol NIL. (if t 'happy) happy 26 (if nil 'happy) nil
EXERCISES Write a function MAKE-EVEN that makes an odd number even by adding one to it. If the input to MAKE-EVEN is already even, it should be returned unchanged. Recall the primitive function NOT: It returns NIL for a true input and T for a false one. Suppose Lisp didn't have a NOT primitive. Show to write NOT using just IF and constants (no other functions). Call your function MY-NOT. Write a function ORDERED that takes two numbers as input and makes a list of them in ascending order. (ORDERED 3 4) should return the list (3 4). (ORDERED 4 3) should also return (3 4), in other words, the first and second inputs should appear in reverse order when the first is greater than the second. 27
THE COND MACRO COND is the classic Lisp conditional. Its input consists of any number of test-and-consequent clauses. The simplified form is: (COND (test-1 consequent-1) (test-2 consequent-2) (test-3 consequent-3). . (test-n consequent-n)) 28
THE COND MACRO Use COND to write a function COMPARE that compares two numbers. If the numbers are equal, COMPARE will say ''numbers are the same. '' If the first number is less than the second, it will say ''first is smaller. '' If the first number is greater than the second, it will say ''first is bigger. '' Each case is handled by a separate COND clause. (defun compare (x y) (cond ((equal x y) 'numbers-are-the-same) ((< x y) 'first-is-smaller) ((> x y) 'first-is-bigger))) (compare 3 5) first-is-smaller (compare 7 2) first-is-bigger (compare 4 4) numbers-are-the-same 29
USING T AS A TEST One of the standard tricks for using COND is to include a clause of form (T consequent) The test T is always true, so if COND ever reaches this clause, it is guaranteed to evaluate the consequent (隨後發生的事). For example: The following function returns the country in which a given city is. If the function doesn't know a particular city, it returns the symbol UNKNOWN. (defun where-is (x) (cond ((equal x 'paris) 'france) ((equal x 'london) 'england) ((equal x 'beijing) 'china) (t 'unknown))) (where-is 'london) england (where-is 'beijing) china (where-is 'hackensack) unknown 30
EXERCISES We can translate any IF expression into a COND expression: (IF test true-part false-part) (COND (test true-part) (T false-part)) Write a version of the absolute value function MY-ABS using COND instead of IF. 31
TWO MORE EXAMPLES OF COND EMPHASIZE changes the first word of a phrase from ''good'' to ''great, '' or from ''bad'' to ''awful, '' and returns the modified phrase: (defun emphasize (x) (cond ((equal (first x) 'good) (cons 'great (rest x))) ((equal (first x) 'bad) (cons 'awful (rest x))))) (emphasize '(good mystery story)) (great mystery story) (emphasize '(mediocre mystery story)) nil (defun emphasize 2 (x) (cond ((equal (first x) 'good) (cons 'great (rest x))) ((equal (first x) 'bad) (cons 'awful (rest x))) (emphasize 2 '(good day)) (great day) (emphasize 2 '(bad day)) (awful day) (emphasize 2 '(long day)) (long day) 32
TWO MORE EXAMPLES OF COND Function COMPUTE takes three inputs. If the first input is the symbol SUM-OF, the function returns the sum of the second and third inputs. If it is the symbol PRODUCT-OF, the function returns the product of the second and third inputs. Otherwise it returns the list (THAT DOES NOT COMPUTE). (defun compute (op x y) (cond ((equal op 'sum-of) (+ x y)) ((equal op 'product-of) (* x y)) (t '(that does not compute)))) (compute 'sum-of 3 7) 10 (compute 'product-of 2 4) 8 (compute 'zorch-of 3 1) (that does not compute) 33
EXERCISES Type in the following suspicious (可疑的) function definition: (defun make-odd (x) (cond (t x) ((not (oddp x)) (+ x 1)))) What is wrong with this function? Try out the function on the numbers 3, 4, and 2. Rewrite it so it works correctly. Write a function CONSTRAIN that takes three inputs called X, MIN, and MAX. If X is less than MIN, it should return MIN; if X is greater than MAX, it should return MAX. Otherwise, since X is between MIN and MAX, it should return X. (CONSTRAIN 3 -50 50) should return 3. (CONSTRAIN 92 -50 50) should return 50. Write one version using COND and another using nested IFs. 34
THE AND OR MACROS Suppose we want a predicate for small (no more than two digit) positive odd numbers. We can use AND to express this conjunction of simple conditions: (defun small-positive-oddp (x) (and (< x 100) (> x 0) (oddp x))) Suppose we want a function GTEST that takes two numbers as input and returns T if either the first is greater than the second or one of them is zero. These conditions form a disjunctive set; only one need be true for GTEST to return T. OR is used for disjunctions. (defun gtest (x y) (or (> x y) (zerop x) (zerop y))) 35
EVALUATING AND OR AND and OR have slightly different meanings in Lisp than they do in logic or in English. The precise rule for evaluating AND is: Evaluate the clauses one at a time. If a clause returns NIL, stop and return NIL; otherwise go on to the next one. If all the clauses yield non-NIL results, return the value of the last clause. Examples: (and nil t t) nil (and 'george nil 'harry) nil (and 'george 'fred 'harry) harry (and 1 2 3 4 5) 5 36
EVALUATING AND OR The rule for evaluating OR is: Evaluate the clauses one at a time. If a clause returns something other than NIL, stop and return that value; otherwise go on to the next clause, or return NIL if none are left. Examples: (or nil t t) t (or 'george nil 'harry) george (or 'george 'fred 'harry) george (or nil 'fred 'harry) fred 37
EXERCISES What results do the following expressions produce? Read the evaluation rules for AND and OR carefully before answering. (and 'fee 'fie 'foe) (or nil 'foe nil) (and 'fee 'fie nil) (and (equal 'abc) 'yes) (or (equal 'abc) 'yes) 38
BUILDING COMPLEX PREDICATES The HOW-ALIKE function compares two numbers several different ways to see in what way they are similar. It uses AND to construct complex predicates as part of a COND clause: (defun how-alike (a b) (cond ((equal a b) 'the-same) ((and (oddp a) (oddp b)) 'both-odd) ((and (not (oddp a)) (not (oddp b))) 'both-even) ((and (< a 0) (< b 0)) 'both-negative) (t 'not-alike))) (how-alike 7 7) the-same (how-alike 3 5) both-odd (how-alike -2 -3) both-negative (how-alike 5 8) not-alike 39
BUILDING COMPLEX PREDICATES The SAME-SIGN predicate uses a combination of AND and OR to test if its two inputs have the same sign: (defun same-sign (x y) (or (and (zerop x) (zerop y)) (and (< x 0) (< y 0)) (and (> x 0) (> y 0)))) SAME-SIGN returns T if any of the inputs to OR returns T. Each of these inputs is an AND expression. The first one tests whether X is zero and Y is zero, the second tests whether X is negative and Y is negative, and the third tests whether X is positive and Y is positive. Examples: (same-sign 0 0) t (same-sign -3 -4) t (same-sign 3 4) t (same-sign -3 4) nil 40
EXERCISES Write a function FUN 1 that squares a number if it is odd and positive, doubles it if it is odd and negative, and otherwise divides the number by 2. Write a predicate PRE 1 that returns T if the first input is either BOY or GIRL and the second input is CHILD, or the first input is either MAN or WOMAN and the second input is ADULT. 41
WHY AND OR ARE CONDITIONALS Why are AND and OR classed as conditionals instead of regular functions? The reason is that they are not required to evaluate every clause. For example, consider the POSNUMP predicate: (defun posnump (x) (and (numberp x) (plusp x))) POSNUMP returns T if its input is a number and is positive. The built-in PLUSP predicate can be used to tell if a number is positive, but if PLUSP is used on something other than a number, it signals a ''wrong type input'' error, so it is important to make sure that the input to POSNUMP is a number before invoking PLUSP. If the input isn't a number, we must not call PLUSP. Here is an incorrect version of POSNUMP: (defun faulty-posnump (x) (and (plusp x) (numberp x))) 42
POSNUMP AND FAULTYPOSNUMP Break 7 [8]> (posnump 3) Break 8 [9]> (faulty-posnump -3) T NIL Break 7 [8]> (posnump -3) Break 8 [9]> (faulty-posnump 3) NIL T Break 7 [8]> (posnump 'a) Break 8 [9]> (faulty-posnump 'a) NIL *** - PLUSP: A is not a real number The following restarts are available: USE-VALUE instead. : R 1 Input a value to be used ABORT : R 2 Abort debug loop ABORT : R 3 Abort debug loop ABORT : R 4 Abort debug loop ABORT : R 5 Abort debug loop ABORT : R 6 Abort debug loop ABORT : R 7 Abort debug loop ABORT : R 8 Abort debug loop ABORT : R 9 Abort main loop 43
BOOLEAN FUNCTIONS Boolean functions are functions whose inputs and outputs are truth values, meaning T or NIL. Another name for boolean functions is logical functions, since they use the logical values true and false. Let's define a two-input LOGICAL-AND function: (defun logical-and (x y) (and x y t)) This ordinary function differs from the AND macro in several respects. (logical-and 'tweet 'woof) t (and 'tweet 'woof) woof (and (numberp 'fred) (oddp 'fred)) nil (logical-and (numberp 'fred) (oddp 'fred)) Error! FRED wrong type input to ODDP. The expression (ODDP 'FRED) causes an error for LOGICAL-AND but not 44 for AND, because AND never evaluates the second clause.
EXERCISES Write LOGICAL-OR. Make sure it returns only T or NIL for its result. 45
- Slides: 45