Title: The Case primitive: matches the evaluated key form against the unevaluated keys by using eql
1The Case primitive matches the evaluated key
form against the unevaluated keys by using eql
- The general format of case is the following
- (case ltkey formgt
- (ltkey 1gt ltconsequent 1-1gt ...
ltconsequent 1-ngt) - (ltkey 2gt ltconsequent 2-1gt ...
ltconsequent 2-ngt) - .....
- (ltkey mgt ltconsequent m-1gt ...
ltconsequent m-ngt)) - Example
- gt (setf object 'sphere r 2)
- 2
- gt (case object
- (circle ( pi r r))
- (sphere ( 4 pi r r)))
- 50.2654824574367
2The key may be an atom or a list in the latter
case the list is searched for the key by means of
the member predicate
- Example
- gt (case object
- ((circle wheel) ( pi r r))
- ((ball sphere) ( 4 pi r r))
- (otherwise 0)) if none of
the clauses is triggered, case - 50.2654824574367 returns NIL, the
otherwise clause (or t) - can
be used to set the returned value. -
3The problem reduction technique
- The idea divide the problem into sub-problems
each of which can - be handled separately.
- Example the both-ends procedure
- (defun both-ends (whole-list)
- (case (length whole-list)
- (0 ....) gt
(0 nil) - (1 ....) gt
(1 (cons (first whole-list) whole-list)) - (2 ....) gt
(2 whole-list) - (t ....))) gt
(t (cons (first whole-list) -
(last whole-list))))) -
4The procedure abstraction technique
- The idea arrange procedures into abstraction
layers. - Example the both-ends procedure
- gt (defun both-ends (whole-list)
- (make-list
- (get-first-el whole-list)
- (get-last-el whole-list)))
- BOTH-ENDS
- gt (defun make-list (el-1 el-2)
- (list el-1 el-2))
- MAKE-LIST
- gt (defun get-first-el (list-1)
- (first list-1))
- GET-FIRST-EL
- gt (defun get-last-el (list-1)
- (first (last list-1)))
- GET-LAST-EL
5Defvar and defparameter define global variables
- (defvar global) declares global as a global
variable. - (defvar global expression) assigns a value to
global - (defparameter global expression) declares
global as a global variable, and assings a
value to it. - Examples
- gt (defvar var-1)
gt (defparameter par-1) - VAR-1
ERROR - gt (defvar var-1 222)
gt (defparameter par-1 77) - VAR-1
77 - gt var-1
gt par-1 - 222
77 - gt (defvar var-1 333)
gt (defparameter par-1 88) - VAR-1
PAR-1 - gt var-1
gt par-1 - 222
88 -
6Singly recursive procedures each recursive call
originates only one new call
- Example compute the n power of m.
- gt (defun exponent (m n)
- (if (zerop n)
- 1
- ( m (exponent m (- n 1)))))
- EXPONENT
- gt (exponent 2 3)
- 8
- The behavior of recursive procedures can be
observed by means of the - trace primitive. Untrace will undo the effect of
trace. These have the - following syntax
- (trace ltprocedure namegt)
- (untrace ltprocedure namegt)
7- gt (trace exponent)
- (EXPONENT)
- gt (exponent 2 3)
- 1gt EXPONENT called with args
- 2
- 3
- 2gt EXPONENT called with args
- 2
- 2
- 3gt EXPONENT called with args
- 2
- 1
- 4gt EXPONENT called with args
- 2
- 0
- 4lt EXPONENT returns value
- 1
- 3lt EXPONENT returns value
- 2
8Doubly recursive procedures each call originates
two recursive calls
- Example compute Fibonacci numbers
- (defun fibonacci (n)
- (if (or ( n 0) ( n 1))
- 1
- ( (fibonacci (- n 1))
- (fibonacci (- n 2)))))
- FIBONACCI
- (fibonacci 5)
- 8
- (trace fibonacci)
- (FIBONACCI)
-
9- (fibonacci 5)
- 1 Entering FIBONACCI, argument-list (5)
- 2 Entering FIBONACCI, argument-list (4)
- 3 Entering FIBONACCI, argument-list (3)
- 4 Entering FIBONACCI, argument-list (2)
- 5 Entering FIBONACCI, argument-list
(1) - 5 Exiting FIBONACCI, value 1
- 5 Entering FIBONACCI, argument-list
(0) - 5 Exiting FIBONACCI, value 1
- 4 Exiting FIBONACCI, value 2
- 4 Entering FIBONACCI, argument-list (1)
- 4 Exiting FIBONACCI, value 1
- 3 Exiting FIBONACCI, value 3
- 3 Entering FIBONACCI, argument-list (2)
- 4 Entering FIBONACCI, argument-list (1)
- 4 Exiting FIBONACCI, value 1
- 4 Entering FIBONACCI, argument-list (0)
- 4 Exiting FIBONACCI, value 1
10Tail recursive procedures a way to make
recursion efficient
- Example compute the number of elements in a list
(version 1) - (defun count-elements-1 (list-1)
- (if (endp list-1)
- 0
- ( 1 (count-elements-1 (rest list-1)))))
- COUNT-ELEMENTS-1
- (setf list-1 '(a b c d))
- (count-elements-1 list-1)
- 1 Entering COUNT-ELEMENTS-1, argument-list
((A B C D)) - 2 Entering COUNT-ELEMENTS-1, argument-list
((B C D)) - 3 Entering COUNT-ELEMENTS-1,
argument-list ((C D)) - 4 Entering COUNT-ELEMENTS-1,
argument-list ((D)) - 5 Entering COUNT-ELEMENTS-1,
argument-list (NIL) - 5 Exiting COUNT-ELEMENTS-1, value 0
- 4 Exiting COUNT-ELEMENTS-1, value 1
- 3 Exiting COUNT-ELEMENTS-1, value 2
- 2 Exiting COUNT-ELEMENTS-1, value 3
- 1 Exiting COUNT-ELEMENTS-1, value 4
11Tail recursion (cont.)
- Example compute the number of elements in a
list (version 2) - (defun count-elements-2 (list-1)
- (count-elements-2-aux list-1 0))
- COUNT-ELEMENTS-2
- (defun count-elements-2-aux (list-1 result)
- (if (endp list-1)
- result
- (count-elements-2-aux (rest list-1) ( 1
result)))) - COUNT-ELEMENTS-2-AUX
- (count-elements-2 list-1)
- 1 Entering COUNT-ELEMENTS-2-AUX,
argument-list ((A B C D) 0) - 2 Entering COUNT-ELEMENTS-2-AUX,
argument-list ((B C D) 1) - 3 Entering COUNT-ELEMENTS-2-AUX,
argument-list ((C D) 2) - 4 Entering COUNT-ELEMENTS-2-AUX,
argument-list ((D) 3) - 5 Entering COUNT-ELEMENTS-2-AUX,
argument-list (NIL 4) - 5 Exiting COUNT-ELEMENTS-2-AUX, value
4 - 4 Exiting COUNT-ELEMENTS-2-AUX, value 4
- 3 Exiting COUNT-ELEMENTS-2-AUX, value 4
12The Tower of Hanoi example
- Version 1 uses a doubly recursive procedure.
- (defun tower-of-hanoi-1 (list-of-disks)
- (if (endp list-of-disks)
- 0
- ( (tower-of-hanoi-1 (rest
list-of-disks)) - 1
- (tower-of-hanoi-1 (rest
list-of-disks))))) - TOWER-OF-HANOI-1
- Version 2 uses a singly recursive procedure.
- (defun tower-of-hanoi-2 (list-of-disks)
- (if (endp list-of-disks)
- 0
- ( 1 ( 2 (tower-of-hanoi-2 (rest
list-of-disks)))))) - TOWER-OF-HANOI-2
13Iteration control structure the DOTIMES primitive
- Dotimes supports iteration on numbers. It has the
following format -
- (dotimes (ltcount parametergt ltupper-bound
formgt ltresult formgt) - ltbodygt)
- When dotimes is entered, the upper-bound form is
evaluated resulting - in a number, say n. Numbers between 0 and n-1 are
assigned to the - count parameter one by one, and for each one of
these numbers the - body is evaluated. Finally, the result form is
evaluated, and its value is - returned by dotimes (if the result form is
missing, dotimes returns NIL).
14Example compute the n power of m.
- (defun exponent-2 (m n)
- (let ((result 1))
- (dotimes (count n result)
- (setf result ( m result)) )))
-
(print result) - EXPONENT-2
- (trace exponent-2)
- (EXPONENT-2)
- (exponent-2 3 3)
- 1 Entering EXPONENT-2, argument-list (3 3)
trace is not very useful here. - 1 Exiting EXPONENT-2, value 27
Incorporating print forms to see - 27
intermediate
results is better.
15Iteration control stucture the DOLIST primitive
- Dolist supports iteration on lists. Its format is
the following - (dolist (ltelement parametergt ltlist formgt
ltresult formgt) - ltbodygt)
- When dolist is entered, the list form is
evaluated returning a list of elements. - Each one of them is assigned to the element
parameter, and the body is - evaluated. Finally, the result form is evaluated,
and its value is returned by - dolist (if the result form is missing, dolist
returns NIL).
16Example count number of as in a list.
- (defun count-a (list-1)
- (let ((result 0))
- (dolist (element list-1 result)
- (when (eql element 'a)
- (setf result ( 1 result))))))
- COUNT-A
- (setf list-1 '(a s d f a s d w a a))
- (A S D F A S D W A A)
- (count-a list-1)
- 4
17DOTIMES and DOLIST can be terminated by the
(return ltexpressiongt) form
- Whenever (return ltexpressiongt) is encountered,
dotimes/dolist - terminates and returns the value of ltexpressiongt.
- Example does the list contain at least n as?
If yes, return them as soon as they are found. - (defun find-n-a (n list-1)
- (let ((result 0) (a-list nil))
- (dolist (element list-1 a-list)
- (cond ((lt n result) (return a-list))
- ((eql element 'a) (setf result
( 1 result)) -
(setf a-list (cons element a-list))))))) - FIND-N-A
- (find-n-a 2 list-1)
- (A A)
18The DO primitive works on both numbers and lists,
and is more general than DOTIMES and DOLIST
- Dolist has the following format
- (do ((ltparameter 1gt ltinitial value 1gt
ltupdate form 1gt) - (ltparameter 1gt ltinitial value 1gt
ltupdate form 1gt) - ..
- (ltparameter 1gt ltinitial value 1gt
ltupdate form 1gt)) - (lttermination testgt ltintermediate
formsgt ltresult formgt) - ltbodygt)
- When do is entered, its parameters are set to
their initial values in parallel - (in the same way as in the let form). If there
are no parameters, an empty - parameter list must be provided. The termination
test is evaluated always - before the body is evaluated. If it succeeds,
intermediate forms and the - result form are evaluated the value of the
result form is returned by do (if - no result form is given, do returns NIL).
19Example compute mn
- Version 1
- (defun exponent-3 (m n)
- (do ((result 1)
- (exponent n))
- ((zerop exponent) result)
- (setf result ( m result))
- (setf exponent (- exponent 1))))
- EXPONENT-3
- (exponent-3 3 3)
- 27
- Version 2
- (defun exponent-4 (m n)
- (do ((result 1)
- (exponent n))
- ( )
- (when (zerop exponent) (return result))
- (setf result ( m result))
- (setf exponent (- exponent 1))))
- EXPONENT-4
- (exponent-4 3 3)
- 27
20DO assigns initial values to parameters
sequentially (like let)
- Example which does not work
- (defun exponent-5 (m n)
- (do ((result m ( m result))
- (exponent n (- exponent 1))
- (counter (- exponent 1) (- exponent
1))) - ((zerop counter) result)))
- EXPONENT-5
- (exponent-5 3 3)
- Debugger warning leftover specials
- gtgtgt Error Determining function in error.
- gtgtgt ErrorUnbound variable EXPONENT
- (ltCOMPILED-FUNCTION 3E196gt ...)
- DO solves the problem.
- (defun exponent-6 (m n)
- (do ((result m ( m result))
- (exponent n (- exponent 1))
- (counter (- exponent 1) (- exponent
1))) - ((zerop counter) result)))
- EXPONENT-6
- A better solution
- (defun exponent-7 (m n)
- (do ((result 1 ( m result))
- (exponent n (- exponent 1))
- (counter exponent (- counter 1)))
- ((zerop counter) result)))
- EXPONENT-7
21The LOOP primitive implements infinite loop if
(return ltexpressiongt) is not encountered
- Loop has the following format
- (loop ltbodygt)
- Example count the number of elements in a list.
- (setf list-1 '(a b c d e))
- (A B C D E)
- (setf count-elements 0)
- 0
- (loop (when (endp list-1) (return
count-elements)) - (setf count-elements ( 1
count-elements)) - (setf list-1 (rest list-1)))
- 5
22The PROG1 and PROGN primitives allow several
forms to be viewed as a group in which forms are
evaluated sequentially.
- Prog1 has the following form
- (prog1 ltform 1gt ltform 2gt ltform ngt).
- All forms are evaluated, and prog1 returns
the value of the first form. - Progn has the following form
- (progn ltform 1gt ltform 2gt ltform ngt).
- All forms are evaluated, and progn returns
the value of the last form. - Example
- (prog1 (eql 'a 'a) (setf a 5))
- T
- (progn (eql 'a 'a) (setf a 5))
- 5
23The FORMAT primitive produces more elegant
printing than PRINT
- Example
- (format t "Hi there!")Hi there! the t
argument says that the output should be -
printed at the terminal. The
returned value is - NIL
NIL - To print a string on a new line, the directive
should be placed at the - beginning of the string
- (format t "Hi there!")
- Hi there!
- NIL
- The directive tells format to print on a new
line, if it is not already on - a new line, while the a directive tells format
to insert the value of an - additional argument which appears after formats
string.
24Examples
- (progn (format t "Student name a" name)
- (format t "Major a" major))
- Student name ANNA
- Major CS
- NIL
- (format t "Student name 10a Major 10a"
name major) - Student name ANNA Major CS
- NIL
- (format t "Student name 20a Major 10a"
name major) - Student name ANNA Major CS
- NIL
25The Read primitive reads a value from the keyboard
- Examples
- (read)hello
the input is typed immediately after read. - HELLO
- (setf greetings (read))hi
the input can be assigned to a variable. - HI
- greetings
- HI
- (setf greetings (read))(hi there!) if
the input contains more - (HI THERE!)
than one symbol it must be enclosed in a list. - greetings
- (HI THERE!)
26Print and read used in combination allow for a
more informative dialog
- Example
- (prog1 (print '(Please enter your name))
- (setf name (read))
- (print (append '(hi) (list name) '(how
are you today?)))) - (PLEASE ENTER YOUR NAME) neli
- (HI NELI HOW ARE YOU TODAY?)
- (PLEASE ENTER YOUR NAME)
- name
- NELI
- Do not use in the print argument for
example, name will be understood - as a reference to a package which does not exist
and will result in an error.
27Read, Terpri and Format in combination can also
be used for a more informative dialog
- Example
- (prog1 (terpri)
- (format t "Please enter your name ")
- (setf name (read)) (terpri)
- (format t "Hi a how are you today?"
name)) - Please enter your name neli
- Hi NELI how are you today?
- NIL
- Notice the space between name and in the
format statement.