;;; The first topic was showing how OR, AND, and IF ;;; (the "conditionals") were different from functions ;;; in that they didn't evaluate all their arguments. ;;; This can come in handy in defining "bullet proof" ;;; functions. The example we used (but didn't evaluate) ;;; was this: ;;; (defun non-negative-integer-p (thing) ;;; (and (integerp thing) ;;; (>= thing 0))) ;;; which would blow up on non-numeric inputs if everything ;;; were pre-evaluated. As it is, the second AND clause ;;; will be evaluated only if the first one returns true. ;;; ;;; This just showed that functions like '+ evaluated ;;; all their arguments. USER(1): (+ 3 (- 4 7)) 0 ;;; IF, on the other hand, does not. If it did, ;;; this would give a divide by zero error no matter what. USER(3): (if T "True branch" (/ 100 0)) "True branch" ;;; We then looked at CONSES and Lists. Point number 1, ;;; you can get CONSes by calling the function CONS, which ;;; takes argument for its CAR and its CDR. ;;; CONS really needs two arguments USER(4): (cons) Error: CONS got 0 args, wanted at most 2. [condition type: PROGRAM-ERROR] ;;; This is how an arbitrary CONS structure prints. (This ;;; is not a proper list, as you can tell from the dot in ;;; the printed representation. USER(5): (cons 'a 3.21) (A . 3.21) ;;; Internally, it's a structure with a CAR and CDR field ;;; (or something like that). USER(6): (inspect *) A dotted list @ #x1072aa29 with 1 element 0-> The symbol A tail-> single-float = 3.21 [#x404d70a4] ;;; Here we were trying to create a CONS cell using the ;;; reader. The mistake is that we need to quote the list. ;;; Otherwise it's a function call USER(8): (a . 3.21) Error: attempt to call `A' which is an undefined function. [condition type: UNDEFINED-FUNCTION] Restart actions (select using :continue): 0: Try calling A again 1: Return a value 2: Try calling a different function 3: Setf the symbol function of A and call it again ;;; This one is successful: another way to read in a ;;; CONS/LIST is through the reader '(...) syntax USER(9): '(a . 3.21) (A . 3.21) ;;; At this point we defined the LISTP function from the ;;; code file. We were testing it on some examples. ;;; A symbol is not a list USER(10): (listp 'foo) NIL ;;; Unless it's the symbol NIL, which *is* a list. USER(12): (listp 'nil) T ;;; This is not a well-formed list because it has a non-list ;;; in its CDR USER(13): (listp (cons 'a 'b)) NIL ;;; But this is a list of one element: it would print as (A) USER(14): (listp (cons 'a nil)) T ;;; You would expect this to print as (A . (B . NIL)) ;;; except as a special favor to you the reader simplifies ;;; the printed representation of proper lists. ;;; One take-away lesson is that if you ever see dots in your ;;; printed output, chances are you're using CONS incorrectly. USER(15): (cons 'a (cons 'b nil)) (A B) ;;; This just stores off the list (A B) in a variable so we ;;; can look at it. USER(16): (setf a-list *) (A B) ;;; First trace of LISTP didn't show the calls to EQ or CONSP, ;;; so we only get a vague idea of what's going on. But notice ;;; how the recursion bottoms out at NIL. USER(17): (trace listp) (LISTP) USER(18): (listp a-list) 0: (LISTP (A B)) 1: (LISTP (B)) 2: (LISTP NIL) 2: returned T 1: returned T 0: returned T T ;;; Now we traced EQ and CONSP, which is dangerous because ;;; they're often used by the system. I edited out all ;;; the superfluous calls below. USER(19): (trace eq consp) (CONSP EQ) USER(20): (listp a-list) 0: (LISTP (A B)) 1: (EQ (A B) NIL) 1: returned NIL 1: (CONSP (A B)) 1: returned T 1: (LISTP (B)) 2: (EQ (B) NIL) 2: returned NIL 2: (CONSP (B)) 2: returned T 2: (LISTP NIL) 3: (EQ NIL NIL) 3: returned T 2: returned T 1: returned T 0: returned T 0: (CONSP T) 0: returned NIL T USER(21): (untrace) NIL