Using Lisp Lisp is a interactive system You can files to be processed as a batch file, but more often than not the programmer is the “main program” Every expression typed a the “>” prompt is “read” and “evaluated” unless it is prefixed with an apostrophe ‘ Typing (exit) at the “>” prompt terminates the xlisp program
Go to computer and play with interactive LISP The best way to learn Lisp is to go to computer and just play with functions, as you see below. Please do this.
Sample Output >(a b c) error: unbound function - a if continued: try evaluating symbol again 1> [ back to top level ] > '(a b c) (a b c) > 1 1 > 1.2 1.2 > a error: unbound variable - a
Sample Output > nil nil > t t > T > '(a (b c) d) > (setq sam 'abc) abc > sam
Arithmetic Functions > (/ 2 3) 2/3 > (/ 1.0 2) 0.5 > (1+ 3) 4 > (mod 2 3) 2 > (mod 5 2) 1 > (+ (* 2 2) (/ 4.0 5) ) 4.8
car=first and cdr=rest > (car '(a b c)) a > (cdr '(a b c)) (b c) > (car nil) nil > (cdr nil) > (first '(a b c)) > (car (cdr '(a b c))) b > (cadr '(a b c))
List Functions > (list 'a 2 'b) (a 2 b) > (list '(a b) '(c d)) > (list sam c) error: unbound variable - c if continued: try evaluating symbol again 1> [ back to top level ] > (list sam 'c) (abc c) > (cons 'a '(b c d)) (a b c d) > (cons '(a b c) 'd) ((a b c) . d) sam had a value ‘abc assigned earlier
List Functions > (append '(a b) '(c d)) (a b c d) > (reverse '(a b c d)) (d c b a) > (length '(a (b c) d))) 3 > > (last '(a b c d)) (d) > (subst 'a 'b '(a b c)) (a a c) > (subst 'a 'b '(a b c b)) (a a c a) Substitutes in list the atom b for atom a
eval and quote > (eval (cdr '(a + 2 3))) cdr creates list (+ 2 3) 5 > (setq a 'b) b > a > b error: unbound variable - b if continued: try evaluating symbol again 1> [ back to top level ] > (set 'a 'b) > (eval (eval ''a)) > 'a a cdr creates list (+ 2 3)
eval and quote > (eval (eval '(quote a))) b > 'a a > (eval '(list '* 9 6)) (* 9 6) > (eval (eval '(list * 9 6))) error: bad function - (* 9 6) 1> [ back to top level ] > (eval (eval '(list '* 9 6))) 54 First eval inside creates a “program with data”, second eval (outside) calculates the value of this “program”
Function Definition > (defun intro (x y) (list x 'this 'is y) ) >; be careful not to quote the arguments when >; defining the function > (intro 2 3) (2 this is 3) > (intro 'stanley 'livingston) (stanley this is livingston)
Predicate Functions > (atom 2) t > (atom '(a b c)) nil > (listp 2) > (listp '(a b c)) > (equal 2 3) > (= 2 3) > (equal 6 (* 2 3))
Predicate Functions > (setq a ‘(1 2)) (1 2) > (equal a ‘(1 2)) t > (eql a ‘(1 2)) nil > (null '()) > (null 2) > nil > (null nil)
Membership Functions > (member 'c '(a b c d)) (c d) > (member 'a '((a b) c d)) nil > (member '(d e) '((a b) c (d e) f)) > (assoc 'c '((a b) (c d) (e f))) This member was not using equal inside And now go to computer and check the following functions
Another look at recursion
(defun my-member(element list) (cond ((null list) nil) Recursive Functions Our own definitions of functions member and length (defun my-member(element list) (cond ((null list) nil) ((equal element (car list)) list) (t (my-member element (cdr list))))) (defun my-length(list) (cond ((null list) 0) (t (+ (my-length(cdr list)) 1))))
(defun count-atoms(list) (cond ((null list) 0) ((atom list) 1) Recursive Functions Counts atoms at all levels of a nested list (defun count-atoms(list) (cond ((null list) 0) ((atom list) 1) (t (+ (count-atoms (car list)) (count-atoms (cdr list)))))) Compare this pattern with patterns of copy and equal functions; this is binary tree recursion
Linear or cdr recursion (length ‘((1 2) 3 (1 (4 (5))))) 3 + 1 (length (3 (1 (4 (5))))) + 1 (length ((1 (4 (5))))) + 1 (length ())
Tree of recursion
Temporary Variable Scopes LET is the Scheme mechanism for temporarily binding values to names (LET ( (name_1 expression_1) (name_2 expression_2) <S-expressions> )) Evaluate expression_i and bind result to name_i Name_1 and name_2 can only be used in the <S-expressions> in the body of the LET static scoping name_i can’t have a different value assigned
More of important functions
let and let*
How to declare local variables (we are going to need this for iterative functions)? (LET ( ( <var1> <val1> ) ... ( <vark> <valk> ) ) <exp1> <expN> ) LET is your way to set up temporary variables. You can initialize each local variable to its value concurrently, then evaluates expressions sequentially. It returns the result of evaluating the last expression. The default value of local variables declared by LET is NIL.
An Example of LET Is the situation of the party likely to be safe for you ? That is, are there more ‘friends’ then ‘enemies’ at the party! (defun is-safe-p ( guests ) (let ( (friendly-guests nil) (hostile-guests nil) ) ;; initializations (setq friendly-guests (identify-friends guests)) (setq hostile-guests (identify-enemy guests)) (> (length friendly-guests) (length hostile-guests) ) ;; are there more friendly than hostile ) )
Let* Let* evaluates ALL of the expressions before ANY of the variables are bound. Let* allows you to evaluate things in the order that they are listed (this is not necessarily true of LET) Example of let*: (let* ((sum (+ 8 3 4 2 7)) ; sum needs value (mean (/ sum 5))) ;; calculate the mean value (* mean mean)) ;; return the mean square ***Most of the time it doesn’t matter, but check this if you keep getting errors.
loop The simplest form of iteration is the – LOOP (loop (<test condition> ) (return <optional var/val>) [body] ) ;end loop
IF and IF-ELSE We will explore the control forms later, here are four to get started if and if-else: (if (condition) then) (if (condition) then else) then – what to return if the condition is true else – what to return if the condition is false these will usually be function calls, but could be values to return (if (/= y 0) (/ x y) 0) – divide x by y or return 0 if y = 0
Example Loop (let ((counter 1)) ; initializing my variable (loop (If (= counter 2) (return (+ counter 5)) (+ counter 1) ))) 6 is returned. (loop (<test condition> ) (return <optional var/val>) [body] )
Another Example (defun test ( ) (let ((n 0) (lis nil)) ; initializing (loop (if (> n 10) (return lis) (setq lis (cons n lis))) ; this is end of if (setq n (+ n 1)) ))) => (10,9,8,7,6,5,4,3,2,1,0) (loop (<test condition> ) (return <optional var/val>) [body] )
dotimes and dolist
Basic Control Structures iteration: dotimes and dolist (dotimes (var num) …) iterates from 0 to num-1, setting var to each value one at a time (dotimes (i n) (print (+ i 1))) – prints the numbers 1 through n (dolist (var lis) …) iterates for each item in the list lis, with var assigned to each (dolist (a lis) (print a)) – prints each item of lis one at a time
dotimes Use dotimes for a counted loop (dotimes (<var--count> <intobj- upper limit> [retobj>]) <body>) (defun test () (let ((sum 0)) (dotimes (x 5 sum) ; x var initialized to 0; 5 is limit; sum is return (print x) (print sum) (setq sum (+ sum x)))))
Dolist Use DOLIST to process elements of a list. This is like cdring down the list – recursion! (dolist (<var><list> [<retobj>] <body>) Evaluates <list> ;which must be a list The var is then bound to each item in list Body is executed in order <retobj> optional, is evaluated and returned
Example: Using dolist to calculate a list of squares ele is the running element of the list (defun sq-list (lst1) (let ((lst2 nil)) (dolist (ele lst1 (reverse lst2) ) ; assigns first element lst1 to ele – again ;remember that were first/resting through the list. ; will go through each element of lst1 ; will return the reverse of lst2 (setq lst2 (cons (* ele ele ) lst2))))) (sq-list ‘(1 2 3 4) (1 4 9 16) Reverse the result list lst2 before returning Conses square of ele to the beginning of list lst2 (dolist ( <var> <list> [<retobj>] <body>)
Another example of dolist: (defun greet (people) (dolist (person people) (print (append ‘(so nice to see you) (list person))))) (setq guests ‘(sally bobo mr-potato-head)) (greet guests) -> (so nice to see you sally) (so nice to see you bobo) (so nice to see you mr-potato-head) (dolist ( <var> <list> [<retobj>] <body>)
do
Iteration DO is an iteration construct that allows for local variables (DO ((var init step)...) ;; assign initial values to variables (test expr1 expr2 ...) ;; evaluate test body1...) if true, evaluate expr1, expr2...; return value of last expr as value of DO and terminate if false, evaluate body1, body2,...; evaluate step expressions and assign to vars; re-evaluate test
Iteration Example: calculating power M to power N (DO ((var init step)...) (test expr1 expr2 ...) body1...) Initialize RESULT to 1, next multiply it byM (DEFUN POWER (M N) ; we raise M to power N (DO ( (RESULT 1 (* M RESULT)) ; multiple by M starting from 1 (EXPON N (- EXPON 1)) ) ; subtract one from EXPON until zero ( (ZEROP EXPON) RESULT) ; NOTE NO BODY!! ) ) When variable EXPON is finally zero, return the result
The Do iteration The DO function (do ( (<var1> [<init1> [<step1>]]) … (<varn [<initn>[stepn>]]) ) (<end-pred><fn>…..<fm> <retobj >) ;; test body-exp1 body-exp2 [<body>] )
Example of Do Countdown: prints numbers from max to 0 (defun iter (max) (do ((num max (- num 1))) ; assign max to num ; subtract 1 from num in loop ((<= num 0) ‘end) ;; this is end condition. (print num))) (do ( (<var1> [<init1> [<step1>]]) … (<varn [<initn>[stepn>]]) ) (<end-pred><fn>…..<fm> <retobj >) ;; test body-exp1 body-exp2 [<body>] )
Another example of do Summing all integers from 0 up to max (defun iter-sum (max) (do ((num max (- num 1)) (sum 0 (+ sum num))) ((<= num 0) sum) ;;; test ;; no body ) In English: Assign max to number, and 0 to sum. Each time through the loop, subtract 1 from num and add sum to number. When Number is less than or equal to 0, return sum. (do ( (<var1> [<init1> [<step1>]]) … (<varn [<initn>[stepn>]]) ) (<end-pred><fn>…..<fm> <retobj >) ;; test body-exp1 body-exp2 [<body>] )
Yet Another example of do (defun reverse-list (ls) ( if (listp ls) (do ( (new-ls () (cons (first old-ls) new-ls)) (old-ls ls (rest old-ls)) ) ((null old-ls) new-ls) ) ) ) [user]: (reverse-list '(3 1 4 1 5 9)) (9 5 1 4 1 3) With do function, you probably don’t need a let --- because it’s in the do function. (do ( (<var1> [<init1> [<step1>]]) … (<varn [<initn>[stepn>]]) ) (<end-pred><fn>…..<fm> <retobj >) ;; test body-exp1 body-exp2 [<body>] )
eval, apply and funcall
EVAL (100 X A) (EVAL <exp>) invokes the evaluation procedure. > (EVAL (LIST ‘+ 4 5)) 9 > (SETQ A ‘X) X > (SETQ X 100) 100 > (CONS (EVAL A) (CONS A ‘( A ) ) ) ? Value of atom A is atom X Value of atom X is 100 (100 X A) Value of (EVAL A) is value of value of A which is value of atom X which is 100
Using EVAL to create fn at run-time Create a function to recognize cups based on the description learned: We define function create-cup-recognizer (defun create-cup-recognizer ( cup-description ) (eval (list ‘defun ‘cup-recognizer ‘( obj ) (list ‘subset (list ‘quote cup-description) ‘obj ) subset tests whether the first arg is a subset of the second arg. > (create-cup-recognizer cup-def) cup-recognizer Which defines function cup-recognizer eval actually creates the definition (defun cup-recognizer (obj ) (subset (quote cup-description) obj)
What if we want to apply a function to an entire list? (MAPCAR <fn-name> <arg1-list> <arg2-list>) > (MAPCAR ‘+ ‘(1 2 3 4) ‘(100 200 300 400) ) (101 202 303 404) > (SETQ action ‘drunk) DRUNK > (SETQ hostile-guests (identify-enemy guests)) (MAPCAR action hostile-guests) Write your own functions identify-enemy and action
APPLY (APPLY <fn-name> <arg-list> ) >(APPLY ‘CONS ‘( A ( B C ) ) ) (A B C) > (APPLY ‘CAR ‘( (A B C) ) ) A > (SETQ OP ‘+) + > (APPLY OP ‘( 5 3 ) ) 8 > (SETQ OP ‘-) - (APPLY OP ‘( 5 3 ) ) 2
A Better Example of APPLY Suppose we want to ``do something’’ to an enemy identified, but the action is determined at run time (based on their actions, degree of threats, etc.). (defun action (fn enemy) (APPLY fn (cons enemy nil) ) ) (defun seize (person) .... ) (defun kill (person) ... ) (defun drunk (person) ... ) > (action ‘seize ‘BlackKnight )
FUNCALL -- A sibling of APPLY (FUNCALL <fn-name> <arg1> <arg2> ...) >(FUNCALL ‘CONS ‘A ‘( B C ) ) (A B C) > (FUNCALL ‘CAR ‘(A B C) ) A > (SETQ OP ‘+) + > (FUNCALL OP 5 3 ) 8 > (SETQ OP ‘-) - > (FUNCALL OP 5 3 )
Useful help facilities (apropos ‘str) list of symbols whose name contains ‘str (describe ‘symbol) description of symbol (describe #’fn) description of function (trace fn) print a trace of fn as it runs :a abort one level out of debugger
A Lisp example: Fibonacci Numbers Writing a function to compute the nth Fibonacci number Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, … fib(0) = 0 fib(1) = 1 fib(n) = fib(n-2) + fib(n-1)
Complete Version (defun fib (n) (cond ((eql n 0) 0) ; base case (t (+ (fib (- n 1)) ; recursively compute fib(n) (fib (- n 2))))))
Examples: Roulette Wheel (DEFUN roulette-wheel (bet-1 bet-2) (compare-with-bet (RANDOM 37) bet-1 bet-2)) (DEFUN compare-with-bet (wheel-spin bet-1 bet-2) (IF (OR (= wheel-spin bet-1) (= wheel-spin bet-2)) (DISPLAY “You won! ”) (DISPLAY “You lost! “)) wheel-spin) (RANDOM X) is a built-in function that returns a value between 0 and X (compare-with-bet) returns wheel-spin as a value (the last s-expression evaluated)
Examples: leap year, length (DEFUN leap-year? (year) (COND ((divisible? year 400) #t) ((divisible? year 100) #f) ((divisible? year 4) #t) (ELSE #f))) (DEFUN length list-of-objects) (COND ((NULL list-of-objects) 0) (ELSE (1+ (length (CDR list-of-objects))))) Can use T or any atom
Examples (continued) (DEFUN maximum (list-nums) (COND ((NULL (CDR list-nums))(CAR list-nums)) (ELSE (LET ((maxtail (maximum (CDR list-nums))) (first (CAR list-nums))) (IF (> first maxtail) first maxtail))))) use recursion to find maximum value in CDR of list, compare to first value in list - maximum is larger of those two
Examples (continued) (DEFUN inc-list (list-nums) (COND ((NULL list-nums) NIL) (ELSE (CONS (1+ (CAR list-nums)) (inc-list (CDR list-nums)) ) returns a new list containing all the values of the argument list incremented by 1
Kathleen Swigger Ron Danielsen Sources Bruce R. Maxim Kathleen Swigger Ron Danielsen