Presentation on theme: "1 COSC3306: Programming Paradigms Lecture 11: Applicative Programming with Lisp Haibin Zhu, Ph.D. Computer Science Nipissing University (C) 2003."— Presentation transcript:
1 COSC3306: Programming Paradigms Lecture 11: Applicative Programming with Lisp Haibin Zhu, Ph.D. Computer Science Nipissing University (C) 2003
2 Versions of LISP Lisp is an old language with many variants Lisp is alive and well today Most modern versions are based on Common Lisp LispWorks is based on Common Lisp Scheme is one of the major variants The essentials haven’t changed much
3 Recursion Recursion is essential in Lisp A recursive definition is a definition in which –certain things are specified as belonging to the category being defined, and –a rule or rules are given for building new things in the category from other things already known to be in the category.
4 Informal Syntax An atom is either an integer or an identifier. A list is a left parenthesis, followed by zero or more S-expressions, followed by a right parenthesis. An S-expression is an atom or a list. Example: (A (B 3) (C) ( ( ) ) )
5 Formal Syntax (approximate) ::= | ::= | ::= ( ) ::= ( ) ::= | ::= | ::= string of printable characters, not including parentheses ::= string of printable characters, not including parentheses
6 LISP facilities LISP facilities: –A method for storing data, –A set of built-in functions, –A set of functional forms, and –A set of operators. Two features –Each data object carries a run-time descriptor giving its type and other attributes. –If a data object has components (is a structured data object), the components are never represented directly as part of the data object; instead a pointer to the component data object is used.
7 Data Objects Every LISP data object, whether a program or data, is either an atom or a cons. An atom is an object that is indivisible in nature and takes two forms: –A literal atom (symbol), which is a string beginning with a letter, and –A numeric atom (number), which is a number used for integer and real arithmetic operations; numbers are their own values.
8 T and NIL NIL is the name of the empty list As a test, NIL means “false” T is usually used to mean “true,” but… …anything that isn’t NIL is “true” NIL is both an atom and a list –it’s defined this way, so just accept it
9 Function calls and data A function call is written as a list –the first element is the name of the function –remaining elements are the arguments Example: (F A B) –calls function F with arguments A and B Data is written as atoms or lists Example: (F A B) is a list of three elements –Do you see a problem here?
10 Quoting Is (F A B) a call to F, or is it just data? All literal data must be quoted (atoms, too) (QUOTE (F A B)) is the list (F A B) –QUOTE is a “special form” –The arguments to a special form are not evaluated '(F A B) is another way to quote data –There is just one single quote at the beginning –It quotes one S-expression
11 Basic Functions CAR returns the head of a list CDR returns the tail of a list CONS inserts a new head into a list EQ compares two atoms for equality ATOM tests if its argument is an atom
20 Other useful Functions (NULL S) tests if S is the empty list (LISTP S) tests if S is a list LIST makes a list of its (evaluated) arguments –(LIST 'A '(B C) 'D) returns (A (B C) D) –(LIST (CDR '(A B)) 'C) returns ((B) C) APPEND concatenates two lists –(APPEND '(A B) '((X) Y) ) returns (A B (X) Y)
21 CAR The CAR of a list is the first thing in the list CAR is only defined for nonempty lists If L is Then (CAR L) is (A B C)A ( (X Y) Z)(X Y) ( ( ) ( ) )( ) ( ) undefined
22 CDR The CDR of a list is what's left when you remove the CAR CDR is only defined for nonempty lists The CDR of a list is always a list
23 CDR examples If L is Then (CDR L) is (A B C)(B C) ( (X Y) Z)(Z) ( ( ) ( ) )( ( ) ) ( ) undefined (X)( )
24 CONS CONS takes two arguments –The first argument can be any S-expression –The second argument should be a list The result is a new list whose CAR is the first argument and whose CDR is the second Just move one parenthesis to get the result: CONS of A ( B C ) gives ( A B C )
25 CONS examples L (CAR L) (CDR L) (CONS (CAR L) (CDR L)) (A B C) A (B C) (A B C) ( (X Y) Z) (X Y) (Z) ( (X Y) Z) ( ( ) ( ) ) ( ) ( ( ) ) ( ( ) ( ) ) ( ) undefined undefined undefined (X) X ( ) (X) CONS puts together what CAR and CDR take apart
26 Dotted Pairs The second argument to CONS should be a list If it isn't, you get a dotted pair CONS of A and B is (A. B) If you get a dotted pair, it's because you gave CONS an atom as a second argument
27 EQ EQ tests whether two atoms are equal –Integers are a kind of atom EQ is undefined for lists –it might work for lists, it might not –but it won't give you an error message As with any predicate, EQ returns either NIL or something that isn't NIL
28 ATOM ATOM takes any S-expression as an argument ATOM returns "true" if the argument you gave it is an atom As with any predicate, ATOM returns either NIL or something that isn't NIL
29 COND COND implements the if...then...elseif...then...elseif...then... control structure The arguments to a function are evaluated before the function is called –This isn't what you want for COND COND is a special form
30 To be continued CONDMemberEqual
31 Special forms A special form is like a function, but it evaluates the arguments as it needs them COND, QUOTE and DEFUN are special forms You can define your own special forms
32 Form of the COND (COND (condition1 result1 ) (condition2 result2 )... (T resultN ) )
33 Defining Functions (DEFUN function_name parameter_list function_body ) Example: Test if the argument is the empty list (DEFUN NULL (X) (COND (X NIL) (T T) ) )
34 Example: MEMBER As an example we define MEMBER, which tests whether an atom is in a list of atoms (DEFUN MEMBER (A LAT) (COND ((NULL LAT) NIL) ((EQ A (CAR LAT)) T) (T (MEMBER A (CDR LAT))) ) ) MEMBER is typically a built-in function
35 Rules for Recursion Handle the base (“simplest”) cases first Recur only with a “simpler” case –“Simpler” = more like the base case Don’t alter global variables (you can’t anyway with the Lisp functions I’ve told you about) Don’t look down into the recursion
36 Guidelines for Lisp Functions Unless the function is trivial, start with COND. Handle the base case first. Avoid having more than one base case. The base case is usually testing for NULL. Do something with the CAR and recur with the CDR.
38 Still more useful Functions (LENGTH L) returns the length of list L (RANDOM N), where N is an integer, returns a random integer >= 0 and = 0 and < N.
39 How EQUAL could be defined (defun equal (x y) ; this is how equal could be defined ; this is how equal could be defined (cond ((numberp x) (= x y)) (cond ((numberp x) (= x y)) ((atom x) (eq x y)) ((atom x) (eq x y)) ((atom y) nil) ((atom y) nil) ((equal (car x) (car y)) ((equal (car x) (car y)) (equal (cdr x) (cdr y))))) (equal (cdr x) (cdr y)))))
40 Lambda expression A lambda expression has the form: (lambda argument-list function-body ) In other words, a lambda expression is somewhat like defun, except that it defines an unnamed function, or it allows the user to define a function with no name. For example, ((lambda(x y) (+ x y)) 2 3) binds x and y to 2 and 3, respectively, and applies +, giving 5 as the returned value of this definition. Even though LISP can be used as a functional programming language, few applications written in LISP are purely applicative. Any realistic LISP program makes heavy use of non-applicative features to achieve a reasonable level of efficiency.
41 The set function The set function is simply an assignment statement and a value of a symbol can be assigned with the general form (setsymbolexpression) in which the expression is assigned to symbol and symbol evaluates to that value until set is applied again. Examine the following examples about set function. eval (set ‘X ‘(A B C) ) (A B C) eval (set ‘B ‘3) 3 eval (set ‘Y ‘A) A eval Y A eval (set ‘Z X) (A B C)
42 The special form let The special form let is a function that provides a way of introducing temporary variables or binding local variables. Temporary variables can serve the result of a computation. The general form of let is (let( (variable1value1) (variable2value2) (variable2value2)… (variablenvaluen) ) (variablenvaluen) )body) in which variable1, variable2, …, variablen, are symbols (let does not evaluate them) that will be used as names on introduced variables. They can be referred to by any code that appears in the body form. When let is invoked, each of value1, value2, …, valuen is evaluated in turn. When they all have been evaluated, the new variables are given their values. Examine the following examples about let function. eval (let ((A 3)) (cons A (let ((A 4)) A) ) ) (3 4) eval (let ((A 3)) (let ((A 4) (B A) ) (cons A B) ) ) (4 3)
43 The special form prog (progn expression1, expression2, …, expressionn) (progn (set ‘x 3) (set ‘y 4) (print (* x y)))
44 Some simple list processing examples (defun member (x l) (cond ((atom l) nil) (cond ((atom l) nil) ((equal x (car l)) (cdr l)) ((equal x (car l)) (cdr l)) (T (member x (cdr l)))) (T (member x (cdr l)))) (defun append (l1 l2) (if (null l1) (if (null l1) l2 l2 (cons (car l1) (append (cdr l1) l2)))) (cons (car l1) (append (cdr l1) l2))))
45 Variations on reverse ;; either of these does O(n^2) cons operations (defun reverse (l) (if (null l) (if (null l) nil nil (append (reverse (cdr l)) (list (car l))))) (append (reverse (cdr l)) (list (car l))))) (defun reverse (l) (and l (append (reverse (cdr l)) (list (car l))))) (and l (append (reverse (cdr l)) (list (car l)))))
46 Flatten (defun flatten (l) (cond ((null l) nil) ; empty list do nothing (cond ((null l) nil) ; empty list do nothing ((atom (car l)) ((atom (car l)) ; cons an atom onto flattend cdr (cons (car l) (flatten (cdr l)))) (cons (car l) (flatten (cdr l)))) ; otherwise flatten head & tail and append results ; otherwise flatten head & tail and append results (t (append (flatten (car l)) (flatten (cdr l)))))) (t (append (flatten (car l)) (flatten (cdr l))))))
47 Higher order functions (defun mapcar (f l) (if (null l) (if (null l) nil nil (cons (apply f (list (car l))) (cons (apply f (list (car l))) (mapcar f (cdr l))))) (mapcar f (cdr l)))))
50 Why Common Lisp? Common Lisp is a high-level, dynamical, extensible language, suitable for symbolic and numerical processing; Modern Common Lisp implementations provide compilers, automatic memory management, multithreading, powerful debuggers; A large number of legacy AI systems written in Lisp exist.
51 Input and Output Print is the most primitive output function > (print (list 'foo 'bar)) (FOO BAR) The most general output function in CL is format which takes two or more arguments: –the first indicates where the input is to be printed, –the second is a string template, –the remaining arguments are objects whose printed representations are to be inserted into the template: > (format t “~A plus ~A equals ~A.~%” 2 3 (+ 2 3)) 2 plus 3 equals 5. NIL
52 Read The standard function for input is read. When given no arguments, it reads from the default place, which is usually standard input. > (defun ask (string) (format t “~A” string) (format t “~A” string) (read)) (read))ask > (ask “How old are you? “) How old are you? 29 29
53 Local Variables One of the most frequently used operators in CL is let. This allows local variables to be used in a function. A let expression has two parts. –First comes a list of instructions for creating variables, each of the form var or (var expression). Local variables are valid within the body of the let. –After the list of variables and values comes the body of expressions, which are evaluated in order. > (let ((x 100) (y 200)) (print (+ x y)) (setq x 200) (print (+ x y)) ‘foo) foo
54 A let example > (defun ask-number () (format t “Please enter a number. “) (let ((val (read))) (if (numberp val) (if (numberp val) val (ask-number)))) val (ask-number))))ASK-NUMBER > (ask-number) Please enter a number. number Please enter a number. (this is a number) Please enter a number
55 Global variables Global variables are visible throughout the program. Global variables can be created by giving a symbol and a value to defparameter or defvar. > (defparameter *foo* 1) *FOO* > *foo* 1 > (defvar *bar* (+ *foo* 1)) *BAR* > *bar* 2 > (defvar *bar* 33) *BAR* > *bar* 2 Note: (defparameter v e) creates a global variable named v and sets its value to be e. (defvar v e) is just like defparameter if no global variable named v exists. Otherwise it does nothing.
56 Global constants You can define a global constant, by calling defconstant. > (defconstant +limit+ 100) +LIMIT+ > (setf +limit+ 99) *** - SETQ: the value of the constant +LIMIT+ may not be altered 1. Break > The plus-something-plus is a lisp convention to identify symbols as constants. Just like star-something-star is a lisp convention to identify global variables.
57 When in doubt When in doubt about whether some symbol is a global variable or constant, use boundp. > (boundp ‘*foo*) T > (boundp ‘fishcake) NIL
58 Assignment There are several assignment operators in Common Lisp: set, setq and setf the most general assignment operator is setf. We can use it to assign both local and global variables: > (setf *blob* 89) 89 > (let ((n 10)) (setf n 2) (setf n 2) n) n)2
59 Setf You can create global variables implicitly just by assigning them values. > (setf x (list ‘a ‘b ‘c)) (A B C) However, it is better lisp style to use defparameter to declare global variables. You can give setf any even number of arguments: (setf a 1 b 2 c 3) is the same as: (setf a 1) (setf b 2) (setf c 3) (setf a 1) (setf b 2) (setf c 3)
60 setf You can do more than just assign values to variables with setf. The first argument to setf can be an expression as well as a variable name. In such cases, the value of the second argument is inserted in the place referred to by the first: > (setf (car x) ‘n) N> (N B C)
61 Functional programming Functional programming means writing programs that work by returning values, instead of by modifying things. It is the dominant programming paradigm in Lisp. Must built-in lisp functions are meant to be called for the values they return, not for side-effects.
62 Examples of functional programming The function remove takes an object and a list and returns a new list containing everything but that object: > (setf lst ‘(b u t t e r)) (B U T T E R) > (remove ‘e lst) (B U T T R) Note: remove does not remove an item from the list! The original list is untouched after the call to remove: > lst (B U T T E R) To actually remove an item from a list you would have to use setf: > (setf lst (remove ‘e lst)) Functional programming means, essentially, avoiding setf, and other assignment macros.
63 How remove could be defined Here’s how remove could be defined: (defun remove (x list) (cond ((null list) nil) (cond ((null list) nil) ((equal x (car list)) ((equal x (car list)) (remove x (cdr list))) (remove x (cdr list))) (t (cons (car list) (remove x (cdr list)))))) (t (cons (car list) (remove x (cdr list)))))) Note that it “copies” the top-level of the list.
64 Iteration When we want to do something repeatedly, it is sometimes more natural to use iteration than recursion. This function uses do to print out the squares of the integers from start to end: (defun show-squares (start end) (do ((i start (+ i 1))) (do ((i start (+ i 1))) ((> i end) ‘done) ((> i end) ‘done) (format t “~A ~A~%” i (* i i)))) (format t “~A ~A~%” i (* i i))))
65 do The do macro is CL’s fundamental iteration operator. Like let, do can create variables, and the first argument is a list of variable specifications. Each element is of the form: (var initial update) where variable is a symbol, and initial and update are expressions. The second argument to do should be a list containing one or more expressions. –The first expression is used to test whether iteration should stop. In the case above, the test expression is (> i end). –The remaining expression in this list will be evaluated in order when iteration stops, and the value of the last will be returned as the value of the do, done in this example. The remaining arguments to do comprise the body of the loop.
66 Dolist CL has a simpler iteration operator for handling lists, dolist. (defun len (lst) “I calculate the length of lst” “I calculate the length of lst” (let ((l 0)) (let ((l 0)) (dolist (obj lst) (setf l (+ l 1))) (dolist (obj lst) (setf l (+ l 1))) l)) l)) Here dolist takes an argument of the form (variable expression), followed by a body of expressions. The body will be evaluated with variable bound to successive elements of the list returned by expression.
67 eval You can call Lisp’s evaluation process with the eval function. > (setf s1 '(cadr '(one two three))) (CADR '(ONE TWO THREE)) > (eval s1) TWO > (eval (list 'cdr (car '((quote (a. b)) c)))) B
68 Functions as objects In lisp, functions are regular objects, like symbols, or strings, or lists. If we give the name of a function to function, it will return the associated object. Like quote, function is a special operator, so we don’t have to quote the argument: > (defun add1 (n) (+ n 1)) ADD1 > (function +) # # > (function add1) # #
69 Just as we can use ‘ as an abbreviation for quote, we can use #’ as an abbreviation for function: > #’+ # # This abbreviation is known as sharp-quote. Like any other kind of object, we can pass functions as arguments. One function that takes a function as an argument is apply. Functions as objects
70 Apply Apply takes a function and a list of arguments for it, and returns the result of applying the function to the arguments: > (apply #’+ ‘(1 2 3)) 6 It can be given any number of arguments, so long as the last is a list: > (apply #’+ 1 2 ‘(3 4 5)) 15 A simple version of apply could be written as follows (defun apply (f list) (eval (cons f list)))
71 Funcall The function funcall is like apply but does not need the arguments to be packaged in a list: > (funcall #’ ) 6 It could be written as: (defun funcall (f &rest args) (eval (cons f args))) (eval (cons f args)))
72 Types In CL values have types, not variables. You don’t have to declare the types of variables, because any variable can hold objects of any type. Though type declaration is never required, you may want to make them for reasons of efficiency. The built-in CL types form a hierarchy of subtypes and supertypes. The type t is the supertype of all types, so everything is of type t.
73 27 fixnum integer rational real number atom t > (typep 27 ‘t) T > (typep 27 ‘atom) T > (typep 27 ‘number) T > (typep 27 ‘real) T > (typep 27 ‘rational) T > (typep 27 ‘integer) T > (typep 27 ‘fixnum) T > (typep 27 ‘vector) NIL