Title: Building user-defined functions: the progressive envelopment technique
1Building user-defined functions the progressive
envelopment technique
- Define combinations of LISP primitives
through a sequence of - experiments thus, complex functions are
build incrementally. - Example the both-ends procedure.
- step 1 set a sample expressions that both-ends
will work on, for example (setf whole-list '(a b
c d)) - step 2 define how to get the first and last
elements - (first whole-list) gt A
- (last whole-list) gt (D)
- step 3 define how to get a list of the two
- (cons ... ...) the results
already obtained are enveloped in a cons form - step 4 envelop the cons form in a defun form
with whole-list as a parameter.
2Building user-defined functions the comment
translation technique
-
- Create an outline of the function in a
comment form, and then - translate comments into LISP forms
- Example the both-ends procedure
- step 1 write a pseudo definition for both-ends
using comments instead of actual forms - (defun both-ends (whole-list)
- get the first element
- get the last element
- combine the two elements in a list)
3The comment translation technique (cont.)
- step 2 gradually translate the comments into
LISP forms - (defun both-ends (whole-list)
- (first whole-list)
- (first (last whole-list))
- combine the two elements in a list)
- step 3 complete the comment translation
- (defun both-ends (whole-list)
- (list
- (first whole-list)
- (first (last whole-list))))
4Binding parameters to initial values the LET
primitive
- The general format of the let form is the
following - (let ((ltparameter 1gt ltinitial-value 1gt)
-
- (ltparameter ngt ltinitial-value mgt))
- ltform 1gt
-
- ltform ngt)
- Example
- (setf whole-list (a b c d))
- (let ((first-el (first whole-list))
- (last-el (last whole-list)))
- (cons first-el last-el))
- (A D)
5Let can be used within defun but let parameters
are local to the let form
- Example
- (defun both-ends-with-let (whole-list)
- (let ((first-el (first whole-list))
- (last-el (last whole-list)))
- (cons first-el last-el)))
- BOTH-ENDS-WITH-LET
- (both-ends-with-let whole-list)
- (A D)
- (defun both-ends-with-let (whole-list)
- (let ((first-el (first whole-list))
- (last-el (last whole-list)))
- (cons first-el last-el))
- (print first-el))
- BOTH-ENDS-WITH-LET
- (both-ends-with-let whole-list)
- Error Unbound variable FIRST-EL in
BOTH-ENDS-WITH-LET
6Let can be used within defun but let parameters
are local to the let form another example
- CG-USER(3) (defun another-example ()
- (let ((a 5)
- (b 6)
- (c 7))
- (print ( a b
c))) - (print ( a b c)))
- Â
- ANOTHER-EXAMPLE
- Â
- CG-USER(4) (another-example)
- Â
- 18
- Error Attempt to take the value of the unbound
variable A'. - condition type UNBOUND-VARIABLE
7LET evaluates its initial-value forms in parallel
before any LET parameter is bound, while LET
does this sequentially.
- Example
- (setf x 'first-value)
- FIRST-VALUE
- (let ((x 'second-value)
- (y x))
- (list x y))
- (SECOND-VALUE FIRST-VALUE)
- (let ((x 'second-value)
(let ((x
second-value)) - (y x))
or
(let ((y x)) - (list x y))
equivalent (list
x y))) - (SECOND-VALUE SECOND-VALUE)
8Predicates for establishing equality between
arguments
-
- EQUAL tests two arguments to see if their
values are the same. - (equal ( 5 5 5) 15)
- T
- (setf list-1 '(This is a list))
- (THIS IS A LIST)
- (equal '(This is a list) list-1)
- T
- (equal 15 15.0) 15 and
15.0 have different - NIL
internal representations - EQUALP tests two arguments to see if they are
the same ignoring case and data type differences - (equalp 15 15.0)
- T
- (equalp '(THIS IS 1) '(this is 1))
- T
9Equality predicates (cont.)
- EQL tests two arguments to see if they are are
the same atom (i.e. number or symbol). - (eql 'atom-1 'atom-1)
- T
- (eql 15 15)
- T
- (eql 15 15.0) 15 and 15.0 are not the
same atom - NIL
- tests to see if two arguments are the same
number. - ( 15 15.0)
- T
- EQ tests to see if two arguments are the same
symbol, i.e. if they are represented by the same
chunk of computer memory. They will be, if they
are identical symbols numbers are not always
represented by the same memory address.
10Member a predicate for testing whether the
first argument is an element of the second
argument
- Example
- (setf list-1 '(It is a nice day))
- (IT IS A NICE DAY)
- (member 'day list-1)
- (DAY)
- (member 'is list-1)
- (IS A NICE DAY)
- (member 'is '((It is) (a nice day)))
- NIL
- Member works only on top-level elements.
11Member tests arguments with eql
- (setf pairs '((a b) (c d) (e f)))
- ((A B) (C D) (E F))
- (member '(c d) pairs) member fails to
identify list membership of a list - NIL
-
- To modify the basic behavior of member, an
appropriate keyword - argument must be used.
- (member '(c d) pairs test 'equal)
- ((C D) (E F))
- (member '(c d) pairs test-not 'equal)
- ((A B) (C D) (E F))
- (member '(a b) pairs test-not 'equal)
- ((C D) (E F))
- (member '(c d) '((c d) (c d)) test-not
'equal) - NIL
12Keywords are self-evaluated symbols they always
start with
- test
- TEST keywords evaluates to themselves
- test symbols evaluate to the value stored
in the variable named by the - symbol
- Error Unbound variable TEST in ltfunction 1
x811040gt - Keyword arguments act as variables, storing
procedure objects. - (setf predicate 'equal) 'equal
produces a procedure object out of
- ltfunction 2 x8D1794gt procedure name
equal. - (member '(c d) pairs test predicate)
- ((C D) (E F))
13More examples
-
- (member 4.0 '(6 7 8 4 9))
- NIL
- (setf predicate ')
- ltfunction 0 xA617E4gt
- (member 4.0 '(6 7 8 4 9) test predicate)
- (4 9)
- (setf predicate 'equalp)
equalp ignores case differences and - ltfunction 2 x8D1D4Cgt
data types. It is the most liberal
equality - (member 4.0 '(6 7 8 4 9) test predicate)
predicate - (4 9)
14Predicates for testing object types
- Atom tests to see if the argument is an atom.
- (atom 'pi)
- T
- (atom pi) pi has a
built-in value of 3.14159265358979 - T
- Numberp tests to see if the argument is a
number. - (numberp 'pi)
- NIL
- (numberp pi)
- T
- Symbolp tests to see if the argument is a
symbol. - (symbolp 'pi)
- T
- (symbolp pi)
- NIL
15Predicates for testing object types (cont.)
- Listp tests to see if the argument is a list.
- (listp 'pi)
- NIL
- (listp '(pi in a box))
- T
- Consp tests to see if the argument is a
non-empty list. - (consp '())
- NIL
- (consp nil)
- NIL
- (consp '(a non-empty list))
- T
- (consp '(a . b))
- T
16Predicates for testing for an empty list
- Null tests to see if the argument is an empty
list. - (null '(not an empty list))
- NIL
- (null 'a) the
argument can be an atom - NIL
- (null nil)
- T
- (null ())
- T
- Endp tests to see if the argument is an empty
list - (endp '(not an empty list))
- NIL
- (endp ())
- T
- (endp 'a) the argument must be a
list - T this is a surprising
result - the expected result is an error.
17Numerical predicates
- Numberp tests to see if the argument is a
number. - Zerop tests to see if the argument is zero.
- Plusp tests to see if the argument is a
positive number. - Minusp tests to see if the argument is a
negative number. - Evenp tests to see if the argument is an even
number. - Oddp tests to see if the argument is an odd
number. - gt tests to see if the arguments are in
descending order. - lt tests to see if the arguments are in
ascending order. - (plusp (- 7))
(gt 8 6 4 2) - NIL
T - (evenp ( 9 5))
(lt 1 3 5 7) - NIL
T - (oddp ( 9 5))
(gt 1 3 5 7) - T
NIL
18Results of two or more predicates can be combined
by means of AND, OR and NOT primitives
- And returns NIL if any of its arguments is NIL,
otherwise returns the value of the last argument - (setf list-1 '(a b c d))
- (A B C D)
- (and (member 'a list-1) (member 'c list-1))
- (C D)
- (and (member 'e list-1) (member 'c list-1))
- NIL
- Or returns NIL if all arguments are NIL,
otherwise returns the value of the first non-NIL
argument. - (or (member 'e list-1) (member 'c list-1))
- (C D)
- (or (member 'e list-1) (member 'a list-1)
(member 'c list-1)) - (A B C D)
19Logical predicates (cont.)
- Not returns T if its argument is NIL.
- (not nil)
- T
- (not ())
- T
- (not (member 'c '(a b d e)))
- T
- (not (member 'c '(a b c d)))
- NIL
- Not behaves the same way as the Null
predicate, because NIL and the empty list ( ) is
one and the same thing.
20Conditionals if, when and unless forms
- If has the following format
- (if lttestgt ltthen formgt ltelse formgt)
- Example
- (setf symbol-or-number 'name)
- NAME
- (if (symbolp symbol-or-number) 'symbol 'number)
- SYMBOL
- (setf symbol-or-number '7)
- 7
- (if (symbolp symbol-or-number) 'symbol 'number)
- NUMBER
21Conditionals (cont.)
- when has the following format
- (when lttestgt ltthen formgt)
- This is equivalent to (if lttestgt ltthen formgt
NIL). - unless has the following format
- (unless lttestgt ltelse formgt)
- This is equivalent to (if lttestgt NIL ltelse
formgt). - when and unless may have unlimited number of
arguments, where the first argument is always the
test, the last argument supplies the value to be
returned, and all others are evaluated for their
side effects.
22Example
- (setf high 98 temperature 102)
- 102
- (when (gt temperature high)
- (setf high temperature)
- 'new-record)
- NEW-RECORD
- high
- 102
23Cond selects among alternatives
- The general form of cond is the following
- (cond (lttest 1gt ltconsequent 1-1gt ...
ltconsequent 1-ngt) - (lttest 2gt ltconsequent 2-1gt ...
ltconsequent 2-ngt) - ....
- (lttest mgt ltconsequent m-1gt ...
ltconsequent m-ngt)), - where (lttest igt ltconsequent i-1gt ...
ltconsequent i-ngt) is called a clause. - A clause whose test is evaluated to non-NIL is
said to be triggered, - and its consequents are evaluated. None of the
rest clauses is - evaluated.
24Example compute the area of object which can be
a circle or a sphere
- (setf object 'sphere R 1)
- 1
- (cond ((eq object 'circle) ( pi r r))
- ((eq object 'sphere) ( 4 pi r r)))
- 12.5663706143592
- The cond form has the following equivalent
formats - (cond ((eq object 'circle) ( pi r r))
- (t ( 4 pi r r)))
- 12.5663706143592
- (cond ((eq object 'circle) ( pi r r))
- (( 4 pi r r)))
here ( 4 pi r r) is both the test , and the - 12.5663706143592
consequent.
25More examples
- (setf p .6)
- 0.6
- (cond ((gt p .75) 'very-likely)
- ((gt p .5) 'likely)
- ((gt p .25) 'unlikely)
- (t 'very-unlikely))
- LIKELY
- (setf breakfast '(eggs bacon toast tea))
- (EGGS BACON TOAST TEA)
- (cond ((gt (length breakfast) 10) 'very-hungry)
- ((not (endp breakfast))
'just-hungry) - (t 'not-hungry))
- JUST-HUNGRY
26Example
- Write a procedure check-temperature which takes
one numerical - argument, and returns VERY-HOT if argument value
is greater than - 100, VERY-COLD if it is less than 0, and NORMAL
otherwise. - (defun check-temperature (temp)
- (cond ((gt temp 100) 'very-hot)
- ((lt temp 0) 'very-cold)
- ('normal)))
- CHECK-TEMPERATURE
- (check-temperature 150)
- VERY-HOT
- (check-temperature 95)
- NORMAL
- (check-temperature (- 7))
- VERY-COLD