Iteration & Block Structure

June 8, 2008 | Filed Under Common Lisp - Touretzky | 1 Comment 

———————————————————
Chapter 11
———————————————————

Iteration and Block Structure

(dotimes (i 4)
(format t “~&I is ~S.” i))
I is 0.
I is 1…

(dolist (x ‘(red green blue) ‘flowers)
(format t “~&Roses are ~S” x))
Roses are RED
Roses are BLUE
Roses are GREEN
FLOWERS

dolist returns the final symbol in its parameters (i.e. Flowers, above)

RETURN can be used to break the loop - returns the value of its argument:

(defun find-odd (num-list)
(dolist (x num-list NIL)
(if (oddp x) x)))

Can set a symbol to hold the result of an operation and pass back:

(defun it-intersection (x y)
(let ((result-set NIL))
(dolist (element x result-set)
(when (member element y)
(push element result-set)))))
-> result-set gets passed back as final element of dolist.

The DO macro:

takes the form (DO ( (var1 initial [update])
(var2 initial [update]))
(test action1… actionN)
body)

return the final action

i.e. (defun count-down ()
(do ((cnt 10 (- cnt 1))
((zerop cnt) (format t “GO!”)
(format t “~S…” cnt)))

need not have a body - all work can be done in the loop and then output as the last action in the test function.

the [update] function need not just be an increment/decrement:
(defun test-fn (x)
(do ((var1 x (rest x)))…

Looping through one list is best done with DOLIST, but can loop through 2 simultaneously with DO:

(defun find-matching-elements (x y)
(do ((x1 x (rest x1))(y1 y (rest y1)))
((or (null x1) (null y1)) nil)
(if (equal (first x1) (first y1))
(retun (first x1)))))

DO* allows sequential setting of variables, like LET*

(defun find-first-odd (number-list)
(do* ((x number-list (rest x))
(e (first x) (first x))
((null x) NIL)
(if (oddp e) (return e))))



Assignment

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 10
———————————————————

Global Variables

(SETF *my-global-variable* 0) -> initializes to zero

(defun sell (n)
(SETF *my-global-variable* (+ *my-global-variable* n))
(format t “Sold ~S glasses today” *my-global-variable*))

If variable set to FOO, then will fail when try to increment. If variable not initialized to zero, then will fail when incremented.

For simple incrementing and decrementing, use INCF and DECF:

(SETF a 2)
(INCF a 4) -> 6
(DECF a 2) -> 4

To PUSH an item onto the top of a list, use PUSH:
(setf mystack nil)
(PUSH ‘item1 mystack) -> (item1)
(PUSH ‘item2 mystack) -> (item2 item1)

Then POP then off again:
(POP mystack) -> item2
mystack -> (item1)

Assignment, incrementing, etc, should generally not be done on local variables, and certainly not on variables that appear in a function’s argument list

(defun bad-style (n)
(format t “~&N is ~S.” n)
(decr n 2)
(format t “~&N is now ~S.” n))

(defun good-style (n)
(let ((p (- n 2)))
(format t “~&N is ~S.” n)
(format t “~&P is ~S.” p)))

However it is permissable to initialize a variable to NIL and assign just once:

(defun get-name()
(let ((first-name NIL))
(format t “First name:”)
(setf first-name (read))
(format t “First name is ~S.” first-name)))

When and Unless:

(WHEN test
body)
(UNLESS test
body)

return NIL if test fails/passes, and last form from body otherwise. Identical to COND, but with cleaner syntax.

Generalized variables
SETF, DECF, etc can be used to change the underlying variable pointed to by a pointer:

(setf x ‘(two plus two equals 4))
(setf (third x) ‘three)
x -> (two plus three equals 4)
(incf (fifth x))
x -> (two plus three equals 5)

(BREAK “Message”) can be used to halt execution, and print out variables, etc into the debugger

(ERROR “message”) can be used to insert a sanity check into the program:

(defun average (x y)
(unless (and (isnumberp x) (isnumberp y))
(error “x and y must be numbers: ~S ~S” x y))
(/ (+ x y) 2.0))

Manipulating Pointers

(defun snip (x)
(setf (cdr x) (cdr (cdr x))))

(setf a ‘(no down payment))
(setf b (cdr a)) -> (down payment)
(snip a) -> (payment)
a -> (no payment)
b -> (down payment)

have shifted the pointer in a from the first cons cell that points to the second cons cell to the third cons cell. note that this does not affect b.

can even create a circular list:
(setf circ (list ‘foo))
(setf (cdr circ) circ) -> (foo foo foo foo…)

List surgery can help to cur down on memory usage, garbage collection and improve speed, but can also cause problems.

Destructive operations on Lists:

May create structures that are hard to print. They are prefixed by N.

NCONC - destructively concatenates:
(setf a ‘(1 2 3)) (setf b ‘(4 5 6))
(append a b) -> (1 2 3 4 5 6)
a -> (1 2 3), b -> (4 5 6)
(nconc a b) -> (1 2 3 4 5 6)
a -> (1 2 3 4 5 6), b -> (4 5 6)

May take any number of arguments and destructively concatenates all of them:
(nconc a b c) -> (1 2 3 4 5 6 7 8 9)
a -> (1 2 3 4 5 6 7 8 9), b -> (4 5 6 7 8 9), c -> (7 8 9)

NSUBST - destructively substitutes:
(setf a ‘(i am a boy))
(subst ‘girl ‘boy a) -> (i am a girl)
a -> (i am a boy)
(nsubst ‘girl ‘boy a) -> (i am a girl)
a -> (i am a girl)

also NREVERSE, NUNION, NINTERSECTION, NSET-DIFFERENCE

REMOVE destructive counterpart is DELETE

Destructive functions are useful for changing small parts of larger structures:

(setf *things*
‘( (object1 a b c)
(object2 d e f)
(object3 g h i)))
(assoc *things* ‘object1) -> (object1 a b c)
(setf (first (assoc *things* ‘object1)) ‘frob)
-> (frob a b c)
(nonc (assoc *things* ‘frob) ‘z)
*things* -> ((frob a b c z)
(object2 d e f)….



Input/Output

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 9
———————————————————

Input/Output

Strings - double quoted:
(setf a “this is a string”) -> “this is a string”
(stringp a) -> T

(format t a) -> this is a string -> NIL

tilde character leads to special operations
~% -> forces newline

(format t “time flies~%like an arrow”) ->
time flies
like an arrow
NIL

~& forces a newline, unless the cursor is already on a new line
(format t “time flies~&~&like an arrow”) ->
time flies
like an arrow
NIL

vs (format t “time flies~%~%like an arrow) ->
time flies

like an arrow
NIL

~S is replaces by the evaluated expressions that follow the string:
(format t “from ~S to ~S in ~S minutes” ‘boston ‘(new york) 55) ->
“from boston to (new york) in 55 minutes”
NIL

(defun square-talk (n)
(format t “~&~S squareed is ~S” n (*n n))

(square-talk 3) -. 3 squared is 9

NB square-talk does not return 9, it returns NIL as per format

(mapcar #’square-talk ‘(1 2 3 4 5))
1 squared is 1
2 squared is 4….
…(NIL NIL NIL NIL NIL)

~A is the same as ~S, but excludes any escape characters:
(format t “test: ~S” “hi mom”) -> test “hi mom”
(format t “test: ~A” “hi mom”) -> test hi mom

READ takes a lisp object from the keyboard and returns the object as its value:

(defun my-square()
(format t “enter any number: “)
(let ((x (READ)))
(format t “your number squared is: ~S~%”
(* x x))))

YES-OR-NO-P / Y-OR-N-P - returns T if YES/Y or NIL if NO/N

(defun riddle()
(IF (YES-OR-NO-P “Do you seek enlightenment:”)
(format t “Then do not ask for it”)
(format t “Then you have found it”)))

WITH-OPEN-FILE - opens a file for read/write access

(defun save-data (item1 item2 item3)
(WITH-OPEN-FILE (STREAM “c:/data.dat” :direction :output)
(format stream “~S~%” item1)
(format stream “~s~%” item2)
(format stream “~s~%” item3)))

(save-data “this” ‘(is a number) 5))

WITH-OPEN-FILE creates a variable that is set to a stream object, and can be READ from:

(defun read-data()
(WITH-OPEN-FILE (stream “C:/data.dat”)
(let* ((item1 (read stream))
(item2 (read stream))
(item3 (read stream)))
(format t “~A~%” item1)
(format t “~A~%” item2)
(format t “~A~%” item3))))
this
(is a number)
5

———————————————————
Notes on chapter 9 exercises

Using recursion to create a list:

(defun generate (m n)
(cond ((equal m n)(list n))
(T (cons m (generate (+ m 1) n)))))

this produces an list of integers from m to n:
(generate -3 3) -> (-3 -2 -1 0 1 2 3)

recurses until m equal to n, then passes back a list containing n only. this is then cons’d with a progressively smaller m number in each recursion as it passes back.

———————————————————

Format parameters:
pad an input with ~10S - makes a 10 wide output (same with ~10A, etc)

(format t “~&~10S~S” “jim” “jones”)
“jim” “jones”

~D and ~F make decimal and floating point numbers respectively, both take prefixes:

~x,yF - x is width (incl decimal point) y is number of decimal places

(format t “~4,2F” 3/2) -> 1.50

End Of File conditions:

When using READ and error will be thrown if you try to recurse-read beyond the end of the file.
To catch this, use 2 condition tags: NIL to indicate an error should not be thrown, and and EOF value that should be returned in the event of reaching the end of the file. the EOF value should be unique - best to cast a fresh cons cell:

(defun read-all-objects (stream eof-ind)
(let ((result (read stream NIL eof-ind)))
(if (eq result eof-ind)
NIL
(cons result (read-all-objects stream eof-ind)))))

This takes a stream and a new cons cell for the EOF flag. Reads from the stream, and if EOF then the EOF flag gets passed back as the value for result. If not EOF, then cons’s the result. NB if EOF, then passes NIL back - this is the last cell, which thus forms a value list.

(defun read-my-file (filename)
(WITH-OPEN-FILE (stream filename)
(let ((contents (read-all-objects stream (list ‘$EOF$))))
(format t “~&File contains ~S objects, which are:” (length contents))))contents)



Recursion

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 8
———————————————————

Recursion:

Double-tail recursion returns one of two results:
(DEFUN anyoddp (x)
(COND ((null x) NIL)
((oddp (first x)) T)
(T (anyoddp (rest x)))))

Single-tail recursion returns one result:
(DEFUN find-first-atom (x)
(COND ((atom x) x)
(T (find-first-atom (rest x)))))

Augmenting recusion loops using the result to build the final answer:
(DEFUN fib (x)
(COND ((NULL x) 0)
(T (+ x (fib (- x 1))))))

List consing recursion - CONSing the result of a recursion into a final list:
(DEFUN square-list (x)
(COND ((null x) NIL)
(T (CONS
(* (first x) (first x))
(square-list (rest x)))))
(square-list ‘(1 2 3 4)) -> (1 4 9 16)

Simultaneous recursion on multiple variables:
(DEFUN my-nth (n lst)
(COND ((zerop n) (first lst))
(T (my-nth (- n 1) (rest lst)))))
(my-nth 2 ‘(a b c d e)) -> c

Conditional Augmentation - tests for a property and uses the result of that test for the base of the recursion, or skips to continue the recursion:

(DEFUN extract-symbols (x)
(COND ((null x) nil)
((symbolp (first x))
(cons (first x)
(extract-symbols (rest x)))
(T (extract-symbols (rest x)))))

(extract-symbols ‘(1 bear and 2 girls)) -> (bear and girls)

CAR/CDR recursion - used to traverse a list of lists (the lists may be uneven - ‘(1 (girl and) (2 . bears)))

(DEFUN find-number (x)
(COND ((numberp x) x)
((atom x) nil)
(T (or (find-number (car x))
(find-number (cdr x))))))

Keeps going until it finds a number to return.

Helping functions:
A function like (COUNT-UP 5) -> (1 2 3 4 5) uses recursion, but is more difficult than COUNT-DOWN, as it must keep track of both the target number, and the number of iterations. Use a helper function:

(DEFUN COUNT-UP (x)
(COUNT-UP-RECURSIVELY 1 x))

(DEFUN COUNT-UP-RECURSIVELY (i n)
(COND ((equal i n) i)
(T (LIST i (count-up-recusively (+ i 1) n)))))



Applicative Programming

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 7
———————————————————

FUNCALL calls a function on some inputs:

(FUNCALL #’cons ‘a ‘b) -> (a . b)

Can also map a function to a symbol:
(SETF fn #’cons)
(FUNCALL fn ‘a ‘b) -> (a . b)

only ordinary functions should be quoted with #’ - macros, symbols or special functions will generate an error (#’IF -> ERROR)

(DEFUN SQUARE (n)
(* n n))
(SQUARE 3) -> 9
(SQUARE ‘(1 2 3 4 5)) ->ERROR

(MAPCAR #’SQUARE ‘(1 2 3 4 5)) -> (1 4 9 16 25)

MAPCAR passes each element of a list to a function.

Pass multiple args by separate lists:
(DEFUN mult (x y)
(* x y ))
(MAPCAR #’mult ‘(2 3 4) ‘(5 6 7)) -> (10 18 28)

(SETF nums
‘( (1 one)
(2 two)
(3 three)))
(MAPCAR #’FIRST nums) -> (1 2 3)
(MAPCAR #’SECOND nums) -> (one two three)
(MAPCAR #’REVERSE nums) -> ((one 1)….)

Lambda functions:
functions defined in-line - can be passed (i.e. to MAPCAR) without having to DEFUN first:

(MAPCAR #’(lambda (n) (* n n)) ‘(1 2 3 4)) -> (1 4 9 16)

FIND-IF returns the FIRST element which matches the predicate/lambda function:
(FIND-IF #’oddp ‘(2 4 7 8 9)) -> 7
(FIND-IF #’(lambda (x) (> x 3)) ‘(1 2 3 4 5)) ->4

(REMOVE-IF #’(lambda (x) (plusp x)) ‘(1 -2 3 -4)) -> (-2 -4)
(REMOVE-IF-NOT #’(lambda (x) (plusp x)) ‘(1 -2 3 -4)) -> (1 3)

; can simply use #’PLUSP X ????

REDUCE applies a function to a list and returns a single result - must be a function that takes two arguments:
(REDUCE #’+ ‘(1 2 3)) -> 6
(REDUCE #’* ‘(2 4 5)) -> 40
Takes the result of each loop of the function and uses the resultant list as one of the input arguments for the next loop.

Can also be used on a list of lists:
(REDUCE #’APPEND ‘(1 2 3) ‘(4 5 6)) -> (1 2 3 4 5 6)
(REDUCE #’UNION ‘(1 2 3) ‘(1 4 5)) -> (1 2 3 4 5)

EVERY applies a predicate to a list, and returns T if every element matches the predicate:
(EVERY #’oddp ‘(1 3 5)) -> T
(EVERY #’(lambda (x) (> x 3)) ‘(4 5 6)) -> T
(EVERY #’(lambda (x) (< x 2)) '(1 2 3)) -> NIL

EVERY on a NIL list will always return T
*** EVERY can also be used on multiple lists, matching each pair in turn:
(EVERY #’> ‘(20 10 5) ‘(18 8 3)) -> T

———————————————————
Notes on Chapter 7 exercises

Look up a value in a paired list with ASSOC:
(SETF tbl ‘((1 one) (2 two)))
(DEFUN LOOK-UP (num)
(assoc num tbl))
(LOOK-UP ‘1) -> (1 one)

Run a test on a list and remove those that pass/don’t pass the test, use REMOVE-IF and REMOVE-IF-NOT:
(DEFUN GET-ODD-NUMS (assoc-list)
(REMOVE-IF-NOT #’(LAMBDA (x) (ODD-P (FIRST x))) assoc-list))
(GET-ODD-NUMS tbl) -> ((1 one))

Run a test and return the first element that matches, use FIND-IF

Does one element of a list come before another? Use MEMBER twice:
(DEFUN cards ‘(1 2 3 4 5))
(DEFUN C1-COMES-FIRST-P (c1 c2)
(MEMBER c2 (MEMBER c1 cards)))
(C1-COMES-FIRST-P ‘1 ‘2) -> (2 3 4 5)
(C1-COMES-FIRST-P ‘2 ‘1) -> NIL

TO run a test on a list where you are comparing each element of a list, and carrying the “winner” forward, use reduce:

(DEFUN high-card (hand)
(REDUCE #’(LAMBDA (card1 card2)
(if (higher-rank-p card1 card2)
card1
card2))
hand))

this runs a test on two cards, returning the higher one and feeding this back into the Lambda as card1 with the next card from hand.

———————————————————

MAPCAR can operate on 2 lists:
(MAPCAR #’* ‘(1 2 3) ‘(4 5 6)) -> (4 10 18)
(MAPCAR #’(LAMBDA (x y) (LIST x ‘gets y))
‘(John Jim Jol) ‘(Job1 Job2 Job3)) -> ((John gets Job1)(Jim gets Job2)..)

FUNCALL works the same as #’
‘CONS -> CONS
#’CONS -> #
#’(LAMBDA (x) (+ x 2)) -> #

Function objects are stored as data, and can be assigned:
(SETF g #’(LAMBDA (x) (* x 10))) -> #
(FUNCALL g 12) -> 120
(G 12) -> error (G is not a function)

Keyword Arguments:
use FROM-END with a non-NIL argument with FIND-IF, REMOVE-IF, REDUCE, etc, to parse from right to left:
(FIND-IF #’ODD-P ‘(1 2 3 4 5) :FROM-END T) -> 5

Especially useful with REDUCE:
(REDUCE #’CONS ‘(a b c d e)) -> ((((A . B) . C) . D) . E)
(REDUCE #’CONS ‘(a b c d e) :FROM-END T) -> (a b c d . e)

Applicative operators:

(DEFUN inalienable-rights (fn)
(funcall fn
‘(life liberty and the pursuit of happiness)))

Any function applied to inalienable-rights will act on the list starting ‘(life..

(inalienable-rights #’length) -> 7
(inalienable-rights #’first) -> life

inalienable-rights will only accept a function that works on a list. CONS requires two lists, so this will not work - would need to wrap in a lambda:

(inalienable-rights #’(lambda (x) (cons ‘high x))) -> (high life liberty…)

alternatively:
(DEFUN func-test (fn)
(funcall fn ‘(1 2 3) ‘(4 5 6)))

(func-test #’cons) -> ((1 2 3) 4 5 6)
(func-test #’(lambda (x y) (mapcar #’* x y))) -> (4 10 18)

By passing back a lexical closure (lambda function) we can make a function that returns a function:

(defun make-greater-than-predicate (n)
#’(lambda (x) (> x n)))

(setf pred (make-greater-than-predicate 3)) -> now have a custom predicate that will take a value x and pass to the lambda function, and returning T if greater than 3.

(find-if pred ‘(1 2 3 4 5 6)) -> 4



List Data Structures

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 6
———————————————————

(APPEND ‘(1 2 3) ‘(4 5 6)) -> (1 2 3 4 5 6)
(APPEND NIL ‘(1 2 3)) -> (1 2 3)
(APPEND ‘(1 2 3) NIL) -> (1 2 3)
(APPEND NIL NIL) -> NIL
(APPEND ‘((1 2) (3 4)) ‘((5 6) (7 8))) -> ((1 2) (3 4) (5 6) (7 8))

APPEND is non-destructive - it copies the first list and makes the final cons cell point to the second list:

(SETF who ‘(only the good))
(APPEND who ‘(die young)) -> (only the good die young)
who -> (only the good)

(APPEND ‘a ‘(b c)) -> ERROR ; ‘a is not NIL terminated (i.e. APPEND cannot place a pointer here
to the CAR of (b c)
(APPEND ‘(a b) ‘c) -> (a b . c)
(APPEND ‘(a b) ‘(c)) -> (a b c)

Comparing CONS, LIST & APPEND:

(CONS ‘rice ‘(and beans)) -> (rice and beans)
(LIST ‘rice ‘(and beans)) -> (rice (and beans))
(APPEND ‘rice (and beans)) -> ERROR

(CONS ‘(here tdy) ‘(gone tmr)) -> ((here tdy) gone tmr)
(LIST ‘(here tdy) ‘(gone tmr)) -> ((here tdy) (gone tmr))
(APPEND ‘(here tdy) ‘(gone tmr)) -> (here tdy gone tmr)

(CONS ‘(eat at) ‘joes) -> ((eat at) . joes)
(LIST ‘(eat at) ‘joes) -> ((eat at) joes)
(APPEND ‘(eat at) ‘joes) -> (eat at . joes)

CONS adds a pointer to the end of the first CONS cell which points to the CAR of the second param.
LIST simply makes a new list using the params given.
APPEND removes the final NIL from each param list and CONses the result.

(REVERSE ‘(1 2 3 4)) -> (4 3 2 1)
(REVERSE ‘(1 2) ‘(3 4)) -> ((3 4) (1 2))

(NTHCDR 0 ‘(1 2 3)) -> (1 2 3)
(NTHCDR 2 ‘(1 2 3)) -> (3)
(NTHCDR 3 ‘(1 2 3)) -> NIL
(NTHCDR 8 ‘(1 2 3)) -> NIL

(DEFUN NTH (x y)
“returns zero-based nth CAR”
(CAR (NTHCDR x y))) ;returns atom??

(LAST ‘(a b c)) -> (c)
(LAST NIL) -> NIL
(LAST ‘(a b c . d)) -> (c . d) ;returns last CONS cell, not the last ATOM

(REMOVE ‘a ‘(b a n a n a)) ->(b n n)
REMOVE is non-destructive:
(SETF my-banana ‘(b a n a n a))
(REMOVE ‘a my-banana) -> (b n n)
my-banana -> (b a n a n a)

Lists as sets:

MEMBER returns the subset of the list following a match, or NIL for none:

(MEMBER ‘b ‘(a b c)) -> (b c)

INTERSECTION returns the overlap of two lists:
(INTERSECTION ‘(a b c) ‘(a d e)) -> (a)
It is the overlap with the first list that is counted:
(INTERSECTION ‘(a a b c) ‘(a b d)) -> (a a b)
(INTERSECTION ‘(a b c) ‘(a a b d)) -> (a b)

UNION returns the union of the two sets, with each item represented once:
(UNION ‘(a b c d) ‘(f g h b)) -> (a b c d f g h)

SET-DIFFERENCE returns what’s left of the first set when the second set has been subtracted:
(SET-DIFFERENCE ‘(a b c) ‘(a b d)) -> (c)

SUBSETP returns T if set 1 is a subset of set2:
(SUBSETP ‘(a b) ‘(a b c)) -> T

Association lists:
(SETF tbl
‘( (one un)
(two deux)
(three trois)))

(ASSOC ‘three tbl) -> (three trois)

(SETF tbl
‘( (one . un)
(two . deux)
(three . trois)))

(RASSOC ‘un tbl) -> (one . un);only works on dotted pairs

(REMOVE-DUPLICATES ‘(a a b b c c)) -> (a b c)

(SET-EXCLUSIVE-OR ‘(a b c) ‘(a d b)) -> (c d)

(SUBST ‘b ‘a ‘(b a n a n a)) -> (b b n b n b)
(SUBST ‘b ‘a ‘((a b) (p a n d a))) -> ((b b) (p b n d b))

SUBLIS does the same as SUBST, but can make many substitutions based on a dotted pairs list:

(SUBLIS ‘((a . b) (c . d)) ‘(a b c d)) -> (b b d d)

EQUAL returns T for two lists whose elements evaluate to the same value:

(SETF x1 ‘(a b c))
(SETF x2 ‘(a b c))
(EQUAL x1 x2) -> T

EQ compares based on actual symbols created:
(EQ x1 x2) -> NIL
(SETF x2 x1)
(EQ x1 x2) -> T

NB. EQ is faster than EQUAL, as it does not need to evaluate.

EQL???

= compares two numbers, irrespective of type:
(= 3 3.0) -> T
(= ‘foo ‘foo) -> ERROR, NOT A NUMBER

EQUALP is case insensitive:
(EQUALP ‘(foo bar) ‘(FOO BAR)) -> T

Keyword Args
(REMOVE ‘a ‘(b a n a n a) :COUNT 2) -> (b n n a)
(REMOVE ‘a ‘(b a n a n a) :COUNT 2 :FROM-END T) -> (b a n n)

(KEYWORDP :COUNT) -> T
(KEYWORDP ‘COUNT) -> NIL

MEMBER tests using EQL - so fine for a list containing symbols and numbers, but not for a list of lists:

(MEMBER ‘a ‘(a b c)) -> (a b c)
(MEMBER ‘(a b) ‘((a b) (c d))) -> NIL

Use the :TEST keyword to change the basis of the test:

(MEMBER ‘(a b) ‘((a b) (c d)) :TEST #’EQUAL)
-> ((a b) (c d))

also works with UNION,INTERSECTION, SET-DIFFERENCE, ASSOC, RASSOC, SUBST.



Variables & Side Effects

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 5
———————————————————

SETF assigns a global variable:
(SETF n 1)
(SETF x ‘(1 2 3))
(LENGTH x) -> 3
(REST x) -> (2 3)

variables have scope - to create a local variable use LET:

(DEFUN MANIP (op x y)
(LET ( (SUM (+ x y)) (PROD (* x y)) )
(COND ((EQUAL op ‘AVG) (/ SUM 2.0))
((EQUAL op ‘MULT) PROD))))

Form is (LET (define-vars) (function using vars) )

To use the results of one var immediately within the define-vars, use LET*

(DEFUN MANIP2 (op x y)
(LET* ( (SUM (+ x y)) (SUMSQ (* SUM SUM)) )
…..

Documentation:

(DEFUN MY-TEST-FUNCTION (x)
“this is my test function”
((+ x 2)))

(DOCUMENTATION ‘my-test-function ‘function) -> “this is my test function”

;;; marks a comment outside of a function
;; marks a comment inside a function on its own line
; marks a comment inside a function alongside some code

The second pointer in a symbol block points to the value of the symbol.

A symbol may have a value and a separate function - i.e. we may define CAR as equal to ROLLS-ROYCE, but the function CAR will be unaffected and the compiler figures out from context which CAR is being referred to.



Conditionals

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 4
———————————————————

Conditionals - IF:

(IF (ODDP 5) ‘odd ‘even) -> odd

COND

(DEFUN COMPARE-TO (x y)
(COND ((EQUAL x y) ‘equal)
((> x y) ‘x-greater-than-y)
((

(DEFUN WHICH-COUNTRY (x)
(COND ((EQUAL x 'LONDON) 'ENGLAND)
((EQUAL x 'PARIS) 'FRANCE)
(T 'UNKNOWN))) ;default fall through

AND and OR macros:

(AND (> 2 1) (< 3 4)) ->T
(OR (> 1 2) (< 3 4)) -> T

AND progresses until it hits a NIL (in which case it returns NIL) or the end of the arguments, in which case it returns the evaluated last argument.

OR progresses until it hit a non-NIL argument (in which case it returns that evaluated argument) or the end of the arguments in which case it returns NIL.

(AND ‘a ‘b ‘c) -> c
(AND ‘(1 2) ‘(3 4)) -> (3 4)

(PLUSP 4) -> T
(PLUSP -4) -> NIL

Boolean functions:
(DEFUN LOGICAL-AND (x y)
(AND (x y T)))

If both x and y and non-NIL, then the function returns the last evaluated argument (in this case, T)

DeMorgan’s Theorum

(and x y) = (not (or (not x) (not y)))
(or x y) = (not (and (not x) (not y)))



EVAL notation

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 3
———————————————————

Numbers, and the symbols NIL and T, evaluate to themselves:

1 -> 1
T -> T
NIL -> NIL

Evaluation rule for lists - the first element is the function to call, the rest are arguments to the function.

(DEFUN my-function (x)
(* x 2))

Evaluation rule for symbols - a symbol evaluates to the value of the variable it refers to

(setf kirk ‘a)
(setf spock ‘a)
(EQUAL kirk spock) -> T
(EQUAL ‘kirk ’spock) -> NIL

3 (1/2) ways to make lists:
‘(1 2 3) -> (1 2 3)
(LIST 1 2 3) -> (1 2 3)
(CONS 1 ‘(2 3)) -> (1 2 3)
(QUOTE (1 2 3)) -> (1 2 3)

A symbol is a block of 5 pointers. The first points to the name of the symbol, the 3rd to the function (the lambda function) which lies behind it.

Name and function can be extracted:
(SYMBOL-NAME ‘EQUAL) -> “EQUAL”
(SYMBOL-FUNCTION ‘EQUAL) -> #

(APPLY #’EQUAL ‘(12 17)) -> NIL
(APPLY #’CONS ‘(as (you like it))) -> (AS YOU LIKE IT)



Lists

June 8, 2008 | Filed Under Common Lisp - Touretzky | Leave a Comment 

———————————————————
Chapter 2
———————————————————

Each element of a LIST is a CONS cell, linked to the next one and terminated with NIL

LENGTH returns the number of elements in a LIST
(LENGTH ‘(1 2 3 4)) -> 4
(LENGTH ‘(1 (2 3) 4) -> 3

(FIRST ‘(1 2 3)) -> 1
(SECOND ‘(1 2 3)) -> 2
(THIRD ‘(1 2 3)) -> 3
(REST ‘(1 2 3)) -> (2 3)

(CAR ‘(1 2 3)) -> 1
(CDR ‘(1 2 3)) -> (2 3)
(CDR (1)) -> NIL

(CADR ‘(1 2 3)) ->2
(CDAR ‘((1 2) (3 4)) -> (2)
(CADDR ‘(1 2 3 4)) -> 3

work backwards from the end - CADDR equals a CDR, followed by another CDR followed by a CAR

CAR and CDR of NIL -> NIL
(THIRD ‘(1 2)) -> NIL

(CONS ‘a ‘(b c)) -> (a b c)
****(CONS ‘a NIL) -> (a)
(CONS NIL NIL) -> (NIL)
(CONS ‘(a) ‘(b c)) -> ((a) b c)

x = (CONS (CAR x) (CDR x))

(LIST ‘a ‘b ‘c) -> (a b c)
(LIST ‘a) -> (a)
(LIST ‘(a)) -> ((a))
(LIST ‘a NIL) -> (a NIL)
(LIST ‘a ‘(b c)) -> (a (b c))

(LISTP ‘a) -> NIL
(LISTP ‘(a)) -> T
(LISTP NIL) -> T
(CONSP ‘a) -> NIL
(CONSP ‘(a)) -> T
(CONSP NIL) -> NIL
(ATOM ‘a) -> T
(ATOM ‘(a)) -> NIL
(ATOM NIL) -> T

NULL returns T for a NIL input, and NIL for a non-NIL input. Use to test for NIL, not to change NIL to T - use NOT in this instance.

Properly formed lists end with NIL. Otherwise they are a dotted list (a b c . d).

CONS will return a dotted list if the last input is an atom and not a cons cell (i.e. a list - which terminates in NIL) or NIL itself:

(CONS ‘a ‘b) -> (a . b)
(CONS ‘a (b)) -> (a b)
(CONS ‘a NIL) -> (a)

LIST always returns a properly formatted list with a NIL terminator, even if the inputs are all atoms.

LENGTH returns the number of CONS cells in a list:

(LENGTH ‘(a b c . d)) -> 3



Next Page →