building user-defined functions: the progressive envelopment technique the idea: define combinations...

25
Building user-defined functions: the progressive envelopment technique The idea: 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) ==> A > (last whole-list) ==> (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.

Upload: delilah-roberts

Post on 14-Dec-2015

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Building user-defined functions: the progressive envelopment technique

The idea: 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) ==> A

> (last whole-list) ==> (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.

Page 2: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Building user-defined functions: the comment translation technique

The idea: 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)

Page 3: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

The 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))))

Page 4: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Binding parameters to initial values: the LET primitive

The general format of the let form is the following:

(let ((<parameter 1> <initial-value 1>)

(<parameter n> <initial-value m>))

<form 1>

<form n>)

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)

Page 5: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Let 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

Page 6: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Let 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)

Page 7: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Predicates for establishing equality between arguments

EQUAL : tests two arguments to see if their values are the same expression.

> (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 differentNIL ; internal representations

EQUALP: tests two arguments to see if they are the same expression ignoring case and data type differences

> (equalp 15 15.0)T> (equalp '(THIS IS 1) '(this is 1))T

Page 8: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Equality predicates (cont.)

EQL : tests two arguments 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.

Page 9: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Member : 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

Note: Member works only on top-level elements.

Page 10: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Member 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

Page 11: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Keywords 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 #<function 1 #x811040>

Keyword arguments act as variables, storing procedure objects.

> (setf predicate #'equal) ; #'equal produces a procedure object out of

#<function 2 #x8D1794> ; procedure name equal.> (member '(c d) pairs :test predicate)

((C D) (E F))

Page 12: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

More examples

Keyword arguments can act as variables; this makes it possible to specify any keyword argument.

> (member 4.0 '(6 7 8 4 9))

NIL

> (setf predicate #'=)

#<function 0 #xA617E4>

> (member 4.0 '(6 7 8 4 9) :test predicate)

(4 9)

> (setf predicate #'equalp) ; equalp ignores case distinctions and

#<function 2 #x8D1D4C> ; data types; the most liberal equality

> (member 4.0 '(6 7 8 4 9) :test predicate) ; predicate

(4 9)

Page 13: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Predicates 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

Page 14: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Predicates 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

Page 15: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Predicates 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.

Page 16: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Numerical 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. > : tests to see if the arguments are in descending order. < : tests to see if the arguments are in acsending order.

> (plusp (- 7)) > (> 8 6 4 2)

NIL T

> (evenp (* 9 5)) > (< 1 3 5 7)

NIL T

> (oddp (* 9 5)) > (> 1 3 5 7)

T NIL

Page 17: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Results 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 retrurns 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)

Page 18: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Logical 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.

Page 19: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Conditionals : the if, when and unless forms

If has the following format:(if <test> <then form> <else form>)

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

Page 20: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Conditionals (cont.)

When has the following format: (when <test> <then form>)

This is equivalent to (if <test> <then form> NIL). Unless has the following format:

(unless <test> <else form>)

This is equivalent to (if <test> NIL <else form>).

Note: both 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.

Page 21: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Example

> (setf high 98 temperature 102)

102

> (when (> temperature high)

(setf high temperature)

'new-record)

NEW-RECORD

> high

102

Page 22: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Cond selects among alternatives

The general form of cond is the following:(cond (<test 1> <consequent 1-1> ... <consequent 1-n>)

(<test 2> <consequent 2-1> ... <consequent 2-n>)

....

(<test m> <consequent m-1> ... <consequent m-n>)),

where (<test i> <consequent i-1> ... <consequent i-n>) 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.

Page 23: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

Example: 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.

Page 24: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

More examples

> (setf p .6)

0.6

> (cond ((> p .75) 'very-likely)

((> p .5) 'likely)

((> p .25) 'unlikely)

(t 'very-unlikely))

LIKELY

> (setf breakfast '(eggs bacon toast tea))

(EGGS BACON TOAST TEA)

> (cond ((> (length breakfast) 10) 'very-hungry)

((not (endp breakfast)) 'just-hungry)

(t 'not-hungry))

JUST-HUNGRY

Page 25: Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments

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 ((> temp 100) 'very-hot)

((< temp 0) 'very-cold)

('normal)))

CHECK-TEMPERATURE

> (check-temperature 150)

VERY-HOT

> (check-temperature 95)

NORMAL

> (check-temperature (- 7))

VERY-COLD