Transcript 4.3 Lisp

Variable Declarations
• Global and special variables
– (defvar …)
– (defparameter …)
– (defconstant …)
– (setq var2 (list 4 5))
– (setf …)
• Local variables
– (let ((x 10)) …)
– (let* ((x 99) …)
1
Global Variables
• Declared using defvar and defparameter:
– (defvar <var name> <init value> <documentation>)
>(defvar number-list nil "A list of numbers")
• Assigned values using setf special form:
– (setf <place> <new value>)
>(setf x 3)
3
>x
3
• Imperative Paradigm Alert (why?)
2
Global Variables, cont.
Global variables are visible throughout the program.
Global variables can be created by giving a symbol and a value to
defparameter or defvar.
> (defparameter *foo* 1)
*FOO*
> *foo*
Note: (defparameter v e)
creates a global variable named v and
sets its value to be e.
1
> (defvar *bar* (+ *foo* 1))
*BAR*
> *bar*
2
> (defvar *bar* 33)
*BAR*
> *bar*
2
(defvar v e) is just like
defparameter if no global
variable named v exists.
Otherwise it does nothing.
3
Global Constants and Variables
•
Define a global constant with defconstant
> (defconstant +limit+ 100)
+LIMIT+
> (setf +limit+ 99)
Error: can't assign a global constant
• readability conventions
– +symbolname+ identifies symbols as constants
– *symbolname* identifies global variables
4
Assignment Statements
• Assignment operators: set, setq and setf
• The most general is setf
• It assigns both local and global variables:
> (setf *blob* 89)
89
> (let ((n 10))
(setf n 2)
n)
2
• Initialized n to 10, then executed all the statements
within the scope of let
5
setf
• Create global variables implicitly by assigning values
> (setf x (list 'a 'b 'c))
(A B C)
• However, it is better lisp style to use defparameter
to declare global variables
• You can give setf any even number of arguments
(setf a 1 b 2 c 3)
is the same as:
(setf a 1)
(setf b 2)
(setf c 3)
6
setf cont.
• You can do more than just assigning values to
variables!
• The first argument to setf can be an expression
as well as a variable name.
• In such cases, the value of the second argument is
inserted in the place referred to by the first:
> x
(A B C)
> (setf (car x) 'n)
N
> x
(N B C)
7
setf Examples
> (setq a (make-array 3))
#(NIL NIL NIL)
> (aref a 1)
NIL
> (setf (aref a 1) 3)
3
> a
#(NIL 3 NIL)
> (aref a 1)
3
> (defstruct foo bar)
FOO
> (setq a (make-foo))
#s(FOO :BAR NIL)
> (foo-bar a)
NIL
> (setf (foo-bar a) 3)
3
>a
#s(FOO :BAR 3)
> (foo-bar a)
3
8
Return or Change?
• The function remove takes an object and a list and returns
a new list where all occurrences of the object were removed
> (setf lst '(b u t t e r))
(B U T T E R)
> (remove 'e lst)
(B U T T R)
• Note: remove does not remove any items from the list!
The original list is untouched after the call to remove:
> lst
(B U T T E R)
• To remove the items from a list you would have to use setf:
> (setf lst (remove 'e lst))
(B U T T R)
• Functional programming means, essentially, avoiding setf, and
other assignments.
9
I/O Input
• (read [<stream>] ...)
– reads the printed representation of an object from a stream
• (read-char [<stream>] ...)
– returns one character and advances the stream pointer
• (read-char-no-hang [<stream>] ...)
– returns one character if one is available (if so, advances the
stream pointer)
• (read-line [<stream>] ...)
– read characters terminated by a newline, returns a string
containing the characters
• (yes-or-no-p [format-string <args>*])
– ask the user a yes/no question
(yes-or-no-p "set x to 3?")
10
I/O Output
•
•
•
print - prints and returns object in lisp format
> (print (list "foo" "bar"))
("foo" "bar")
("foo" "bar")
princ - prints for readability, without control characters e.g. " ", returns object lisp
format
> (princ "hello")
hello
"hello"
format - the most general output function
(format <stream> <control-string> <arg>*)
– stream t prints to *standard-output*
– returns NIL
– the second argument is a string template,
– the remaining arguments are objects to be inserted into the template:
> (format t "~A plus ~A equals ~A." 2 3 (+ 2 3))
2 plus 3 equals 5.
NIL
11
Developing Recursive Functions
• Recursive function calls a copy of itself
1. Do error checking first (if needed)
2. Check for base cases (non-recursive cases)
3. Recursion
• must be on a smaller problem
• If number – closer to base case
• If list – shorter or less complex
• Avoid infinite loops!!!!
• out of stack space error
12
Exercise - Write a filtering function
• A function to filter out negative numbers from a list of
numbers.
• Examples:
> (filter-negatives '(1 -1 2 -2 3 -4))
(1 2 3)
> (filter-negatives '("string"))
List must contain only numbers
> (filter-negatives '(-1 -2 -2 -3 -4))
NIL
> (filter-negatives '(9 10))
(9 10)
13
Filter-negatives
1. Error checking
• Is argument a list?
• Continue
• End with error message
2. Test for base case(s)
• Is the list empty?
• Return the empty list ()
3. Test the first item
• Is it a number?
• If not – error message
• Is it a negative number?
• Ignore it - recurse on the rest of the list and return that result
• Is it a positive number?
• Add that number to the result of recursion on the rest of the list
14
Start the function
(defun filter-negatives (inlist)
"takes one argument, a list of numbers
and returns a list containing all the
non-negative numbers in the input"
(cond ; make decisions
; error – not a list?
; base case – empty list?
; what are the more complex cases?
; check first item in list -; not a number? Error or ignore
; negative number?
; Ignore, process remaining items
; positive number?
; Add to result, process remaining items
) )
15
filter-negatives
(defun filter-negatives (inlist)
"takes one argument, a list of numbers and
returns a list containing all the nonnegative
numbers in the input"
(cond ; make decisions
((not (listp inlist); not a list?
(princ "Argument must be a list" )
(terpri) ; print return after string
(list)) ; return an empty list
16
filter-negatives
(defun filter-negatives (inlist)
(cond ; make decisions
((not (listp inlist); not a list?
(princ "Argument must be a list" )
(terpri) ; print return after string
(list)) ; return an empty list
; base case – empty list?
((null inlist)
(list)) ; return an empty list
17
Recursive Cases – Not a Number
; what are the more complex cases?
; check first item in list
; not a number? Error or ignore
18
Recursive cases – Negative Number
; negative number?
; Ignore, process remaining items
19
Recursive Cases – Positive Number
; positive number?
; add to result, process remaining items
20
filter-negatives
;;; Error checking on input - list of numbers
;;; The base case, the list is empty so return nil
;;; if first item in arg is positive, add it to the result of recursion
;;; if it is negative, throw it away, return = result of recursion
(defun filter-negatives (inlist)
(cond
((not (listp inlist))
; 1st test
(princ "Argument must be a list")
; print message
(terpri) (list))
; return empty list, quit
((null inlist) (list))
; 2nd test - out of items
((not (numberp (car inlist)))
; 3rd test - not a number
(princ "List must contain only numbers") ; print message
(terpri) (list))
; return empty list, quit
((>= (car inlist) 0)
; 4th test - positive number
(cons (car inlist)
; add 1st to result of
(filter-negatives (cdr inlist))))
; recursion on rest
((< (car inlist) 0)
; 5th test - negative number
(filter-negatives (cdr inlist))
; ignore 1st, return value
) ) )
; = recursion on rest
; Note: the last test could have been t (true)
21
filter-negatives
• filter.lisp
• www2.hawaii.edu/~janst/313/lisp/filter.lisp
22
&optional in parameter list
• Gives a name to additional variable(s) in
a parameter list.
(defun func (arg1 &optional arg2)…)
• No error if variable(s) are present or not
(func 10)
(func 10 20)
• Default value can be specified
(defun func (arg1 &optional (arg2 init2))…)
(func 10) = (func 10 init2)
23
&key in parameter list
• Several optional parameters,
• Keywords rather than order is used to match
formal names to actual names
> (defun func (width &key ((:height h)) ((:depth d)))
(format t "w = ~d, h = ~d, d = ~d" width h d))
FUNC
> (func 1 :height 2 :depth 3)
w = 1, h = 2, d = 3
NIL
> (func 1 :depth 3 :height 2)
w = 1, h = 2, d = 3
NIL
24
&rest in parameter list
• Allows to accept any of number of parameters
• Such parameters form a list
> (defun list2 (&rest x) x)
LIST2
> (list2 1 2 3 4 5)
(1 2 3 4 5)
25
Exercise: count-occurrences
• Write a function that takes two parameters
• The first is an item to look for
• The second parameter is a list
• Returns the number of times item is found
• Example:
> (count-occurrences 'a
'(a (a c d a) (c b a)))
1
•
www2.hawaii.edu/~janst/313/lisp/count-occurrences.lisp
26
count_all_items
• Now write a function that takes the same
two parameters
• The first is an item to look for
• The second parameter is a list
• The function returns the number of times the item occurs
in the list at any level ofnesting
• Example:
>(count_all_items 'a
'(b (a c d a) (c a b)))
should return 3
27
Exercise: make-change
•
Write a function that calculates change (in US currency)
> (make-change 123)
((1 DOLLARS) (2 DIMES) (3 PENNIES))
(defconstant *us-currency*
'((100 dollars) (50 half-dollars)
(25 quarters) (10 dimes)
(5 nickels) (1 pennies)))
28
make-change
(defun make-change (number)
(
; error checking
; base case(s)
; recursive case(s)
• www2.hawaii.edu/~janst/313/lisp/makechange.lisp
29