*current-package*
is the name of the current package. Any
variables or functions you define while be defined within that package. The use
of different packages allows packages to define variables and
functions with names that might be used in other packages, without having to
worry about name "collisions".
Every symbol has a full name, of the form:
packageName::symbol-name
Shorter references are of the forms:
packageName:symbol-name (syntax works if package has been imported)
symbol-name (only works if *current-package* is that of symbol.)
"atom", not "atomp". Inconsistent naming conventions is one of my pet peeves about Lisp.
Here's a predicate that tests to see if the car of the arg is an atom:
(defun car-atomp (x) (atom (car x)))A problem: what if x has no car?
>(append '(a b) '(c d)) (A B C D)
(defun 3-max (a b c) ;Returns whichever of three given args is largest (let ((ab (max a b)) ;Defs a local variable, ab, set equal to max of a & b bc) ;Defines a local variable, and sets it to NIL, ; because no initial value is given. ;; ab and bc are defined within the LET statement. (setq bc (max b c)) (max ab bc))) ;Because this is the last form in the LET, it will be ;the value of the LET. Because the LET is the last form ; of 3-MAX, 3-MAX's value will assume LET's.Of course a far simpler implementation of 3-max is:
(defun 3-max (a b c) (max a b c))
(defun recursive-length (list) (if (null list) 0 (1+ (recursive-length (cdr list))))) (defun factorial (n) ;Recursive bindings protect us. (if (zerop n) 1 (* n (factorial (1- n)))))(MEMBER elt list) returns the largest tail of LIST whose CAR = ELT. If no match, returns NIL.
(member 'a '(b c a d f))MEMBER also takes keyword arguments. Keyword args are position independent (except that they must follow standard arguments), using special tokens, called keywords, to distinguish one from another.
? (member 3 '(5 4 3 2 1) :test #'>) ; Use > instead of eql for "equality" test. (2 1) ? (member 3 '(5 4 3 2 1) :test #'> :key #'1+) ; Apply 1+ to elts before "equality" test (1) ?
(defun recursive-member (elem list) ;Not quite like MEMBER, why? (cond ((null list) nil) ;Classic terminator for recursion on lists. (or (equal elem (first list)) ;[Use of OR as a conditional] (recursive-member elem (rest list)))))Doesn't return tail.
Now is a good time to see how your Lisp's trace facility works: trace recursive-member.
(defun recursive-member (elem list) ;More like MEMBER (cond ((null list) ;Terminator for failure. nil) ((equal elem (first list)) ;Terminator for success. list) ;Return's matching tail. (t (recursive-member elem (rest list)))))The relationship between recursion and induction. In designing a recursive function, simply make sure that it works for the base case (0, NIL, e.g.). Then, assuming it works for the N case, show that it works for the N+1 case. Think recursively with lists. They are basically tree stuctures, so recursion is usually a good bet....
(defun our-subst (new old list) (cond ((equal old list) new) ((atom list) list) ;No more subst's (t (cons (our-subst new old (car list)) ;Subst in CAR (our-subst new old (cdr list)))))) ;Subst in CDRIn this example, "list" is actually acting as a tree. The algorithm is doubly-recursive: the third conditional clause recurses down both the CAR and the CDR of the given arg.
> (our-subst 'a 'b '(b c d (f b a) (g (h b i) j))) (A C D (F A A) (G (H A I) J))To see the recursion in action, we can use the trace facility, or we can add a few print statements...
(defun our-subst (new old list &optional (depth 0)) (format t "~VTIncoming, LIST = ~a~%" depth list) ;; [~5T would tab to column five. 'V', used in place of a prefix argument to ;; a FORMAT directive causes the argument to be taken from the arg list to ;; the FORMAT. So ~VT causes a tab to the column identified by the next ;; argument in FORMAT, DEPTH.] (let ((result ;Save the return value for later printing (cond ((equal old list) new) ((atom list) list) ;No more subst's (t (cons (our-subst new old (car list) (1+ depth)) ;Subst in CAR (our-subst new old (cdr list) (1+ depth))))))) ;Subst in CDR (format t "~VTReturning: ~a~%" depth result) result)) ;Return value of the function
> (compress '(a a a b c c d e e)) ((3 A) B (2 C) D (2 E)) (defun compress (x) ; Need a wrapper around the recursive fnct (if (consp x) (compr (car x) 1 (cdr x)) x)) (defun compr (elt ; Element of list now being compressed n ; How many have already been seen/compressed lst) ; Remaining (uncompressed) list. (if (null lst) (list (n-elts elt n)) (let ((next (car lst))) (if (eql next elt) (compr elt (+ n 1) (cdr lst)) (cons (n-elts elt n) (compr next 1 (cdr lst))))))) (defun n-elts (elt n) (if (> n 1) (list n elt) elt))Recursion is not always right, though:
(defun fib (n) (cond ((or (equal n 1) (equal n 2)) 1) (t (+ (fib (1- n)) (fib (- n 2))))))It needlessly computes each FIB term an exponential number of times. For example, (fib 98) is computed for (fib 99) and (fib 100). Think about how many times (fib 2) is calculated during calculation of (fib 100). A better solution would be to 'remember' previous invocations of FIB, and to recall those previously calculated values. We'll see how to do this when we cover closures.
Anyway, this example shows that sometimes iteration is better....
(defun calc-length (x) ; Return number of elts of given list (x). (do ((tmp x) (length 0)) ((atom tmp) length) (setq tmp (cdr tmp)) (setq length (1+ length))))A more concise version. Note that the loop now has no actual body! All the work is done in the stepping operations:
(defun calc-length (x) ; Return number of elts of given list (x). (do ((tmp x (cdr tmp)) ; Use of CDR is classic technique for itering through a list. (length 0 (1+ length))) ((atom tmp) length))) ; NIL is an atom and a CONS. ? (calc-length '(a b c)) 3 ? (atom nil) T ? (calc-length 'a) 0 ? (calc-length '()) 0
(defun my-reverse (x) (do ((tmp x (cdr tmp)) (reversed nil (cons (first tmp) reversed))) ((null tmp) reversed))) (defun print-list (x) (do ((tmp x (cdr tmp))) ((null tmp) 'bye-bye) (print (car tmp)))) (defun print-list (x) ; For simple iter across list elems, DOLIST is nice shortcut (dolist (cur x) (print cur))) (defun print-list (x) (do ((tmp x (cdr tmp)) ;Is anything wrong with this? (cur (car tmp) (car tmp))) ;Yes, because first TMP here is free var. ref. ((null tmp) 'bye-bye) (print cur))) (defun print-list (x) (do* ((tmp x (cdr tmp)) (cur (car tmp) (car tmp))) ;Is anything wrong with this? ((null tmp) 'bye-bye) ;NO, because (CAR NIL) = NIL (print cur)))The RETURN function is used to abort looping constructs primarily. Unlike C or PASCAL, functions in LISP only rarely use an explicit RETURN. That is because all functions in LISP return values. Recall the the value of a function is the value of the last form executed within that function.
(defun print-list-to-stop (x) (do ((tmp x (cdr tmp))) ((null tmp) '***completed***) (if (equal (car tmp) 'stop) (return '***aborted***)) (print (car tmp))))