Assignment

June 8, 2008 | Filed Under Common Lisp - Touretzky 

———————————————————
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)….

Comments

Leave a Reply