* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Download Function Design
Survey
Document related concepts
Transcript
Function Design in LISP
Program Files
LISP programs are plain text
– DOS extensions vary; use .lsp for this course
(load “filename.lsp”)
Can use Unix-style paths
– (load “c:/Work/Comp2043/A4/myFile.lsp”)
– (load “A4/myFile.lsp”)
– (load “A4\\myFile.lsp”) OK in Windows
Comments
For this course:
– identify file as we did with Prolog programs
– function comments similar to predicates
– also say what gets returned
;; (fib N)
;; -- returns the Nth Fibonacci number, N > 0
;; -- no error checking (infinite loop if N =< 0)
Comments
Many similar functions
– conversion functions, for example
One comment for all
;; (print-no-X-warning N)
;; -- where X in {student, course, section}
;; -- print a warning message that there is no
;; object X corresponding to N
;; -- N is a student number, course number, etc.
Functional Cohesion
You should be able to describe what your
function does in a simple sentence
– how it’s doing it may require more explanation
If you need the word “and”, you’re probably
doing too much!
– see if you can split it into two functions…
– …or move some functionality into another fn
Non-Cohesive Function
;; (squeeze-input)
;; -- rewrite output getting rid of excess spaces
…
;; (punc L)
;; -- checks whether L is punctuation
;; and if it isn’t it prints a space
;; and continues “squeezing” input
Cohesive Function
;; (squeeze-input)
;; -- rewrite output getting rid of excess spaces
…
;; (punc L)
;; -- says whether L is a punctuation character
Let (squeeze-input) worry about printing
spaces and continuing squeezing input
Writing Functions in LISP
First (as usual): understand what’s required
– what are you given?
– what is the value to return?
Second: plan how to get result
– break down into its conditions (if any)
– identify easy cases
– break harder cases down into parts
Functions and Lists
List argument generally needs to be broken
into parts
– (first L) – operate on this directly
– (rest L) – recur on this
Mapped parts need to be re-combined
– maybe some math function – atomic result
– usually using CONS – list result
Implementing a Plan
Plan is in steps:
– calculate this
– use it to calculate that
All must be combined into one function call
Early calculations become arguments for
later ones
– will evaluate from the inside out
Plus-1 List: Imperative
Add one to each element of a list
plus1List(L)
if (L == nil)
variables not necessary
return nil;
else
var newFirst first(L) + 1;
var newRest plus1List(rest(L));
return cons(newFirst, newRest);
Plus-1 List: Imperative
Add one to each element of a list
plus1List(L)
if (L == nil)
replace conditional command
return nil;
with conditional expression
else
return cons(first(L) + 1,
plus1List(rest(L)));
Plus-1 List: Imperative
Add one to each element of a list
plus1List(L)
return (L == nil) ?
nil
now functional: rewrite to LISP
:
cons(first(L) + 1,
plus1List(rest(L)));
Plus-1 List: LISP
Add one to each element of a list
(defun plus1List (L)
(if (null L)
nil
make more “idiomatic”
(cons (+ (first L) 1)
(plus1List (rest L)))))
Plus-1 List: LISP
Add one to each element of a list
(defun plus1List L
(unless (null L)
(cons (+ (first L) 1)
(plus1List (rest L)))))
(unless (null Arg)
(cons (…(first Arg)…)
(…(rest Arg)…)))
programming idiom
translating a list
Functional Abstraction
Complicated (or repeated) steps should get
their own function definitions
– apply same process again
– understand what you want out of the function
(don’t let the code control you)
Laziness is a virtue
– leave it for later
– but make sure you understand it, first
Example
Standard deviation (population)
– square root of the average of the deviations
– given a list of numbers, returns a number
Functional abstraction
– square root is built in, average we can build
– deviations??? Time to be lazy!
(defun stdevp (L) (sqrt (average (deviations L))))
Sub-Problems
Average
– given a list of numbers, return a number
– add up the numbers, divide by the # of numbers
– left as an exercise
Deviations
– deviation = difference from average, squared
– given a list of #s, return another list of #s
Deviations
Need the average of the list
– use the average function: (average L)
Need to find the deviation for every element
in the list – its difference from the average
– time to be lazy again – another function
– given a list & its average, return list of
deviations
– (deviation-list L (average L))
Deviation List
Need to process a list & return a list
– break down list (using first & rest)
– calculate deviation (separate function on first,
recursion on rest)
– reconstruct list (using cons)
Unless the list is empty, of course
(unless (null L) (cons (…(first L)…) (…(rest L)…)))
Calculation of deviation of first
Calculation of deviations of rest
Calculating a Single Deviation
Given a number and the mean, return a
number (its deviation)
– their difference, squared
– use expt for squaring (expt x 2) = x2
(defun calculate-deviation (Value Mean)
(expt (– Value Mean) 2))
List of Deviations
(defun deviation-list (L M)
(unless (null L)
(cons
(calculate-deviation (first L) M)
(deviation-list (rest L) M)
) ) )
(defun deviations (L)
(deviation-list L (average L)))
Function Call
Calculate standard deviation (population) of
the list (5 10 15)
> (stdevp ‘(5 10 15))
(sqrt (average (deviations ‘(5 10 15))))
(average (deviations ‘(5 10 15)))
(deviations ‘(5 10 15))
(deviation-list ‘(5 10 15) (average ‘(5 10 15)))
= (deviation-list ‘(5 10 15) 10)
Function Call (cont.)
(deviation-list ‘(5 10 15) 10)
(unless (null ‘(5 10 15)) (…))
= (unless NIL (cons (…) (…)))
(cons (calculate-deviation …) (…))
(calculate-deviation (first ‘(5 10 15)) 10)
= (calculate-deviation 5 10)
(expt (– 10 5) 2) = 25
= (cons 25 (deviation-list (rest ‘(5 10 15)) 10))
Function Call (cont.)
(deviation-list ‘(10 15) 10)
(unless (null ‘(10 15)) (…))
= (unless NIL (cons (…) (…)))
(cons (calculate-deviation …) (…))
(calculate-deviation (first ‘(10 15)) 10)
= (calculate-deviation 10 10)
(expt (– 10 10) 2) = 0
= (cons 0 (deviation-list (rest ‘(10 15)) 10))
Function Call (cont.)
(deviation-list ‘(15) 10)
(unless (null ‘(15)) (…))
= (unless NIL (cons (…) (…)))
(cons (calculate-deviation …) (…))
(calculate-deviation (first ‘(15)) 10)
= (calculate-deviation 15 10)
(expt (– 10 15) 2) = 25
= (cons 25 (deviation-list (rest ‘(15)) 10))
Function Call (cont.)
(deviation-list ‘() 10)
(unless (null ‘()) (…))
= (unless T (cons (…) (…))) = NIL
= (cons 25 NIL) = (25)
= (cons 0 ‘(25)) = (0 25)
= (cons 25 ‘(0 25)) = (25 0 25)
= (average ‘(25 0 25)) = 16.6667
= (sqrt 16.6667) = 4.0825
Tweaking the Code
Deviations just calls deviation-list with own
argument plus another
Could be combined into one function
– make the mean an optional argument
– default value – average of the given list
(defun deviations (L &optional (M (average L))) …)
Will call average if & only if no mean given
Combined Deviations Code
(defun deviations (L &optional (M (average L)))
(unless (null L)
(cons
(calculate-deviation (first L) M)
(deviations (rest L) M)
) ) )
Note: important to pass M in recursive call
– else calculates average of (10 15) = wrong
Optional Parameters
Use &optional in parameter list
– everything before &optional is required
– if not given use NIL – or default value (next)
> (defun opt-args (a &optional b c) (list a b c))
OPT-ARGS
> (list (opt-args 1) (opt-args 2 3) (opt-args 4 5 6))
((1 NIL NIL) (2 3 NIL) (4 5 6))
Default Values
For optional arguments
– list with parameter name & default value
– default calculated at call time
> (defun def-args (a &optional (b 5)) (list a b))
DEF-ARGS
> (list (def-args 1) (def-args 2 3))
((1 5) (2 3))
Correlation
Write a function to calculate the correlation
between two lists
– the two lists must be the same length
Understanding
– given two lists (same length)
– returns a number
– formula to follow
Calculating a Correlation
Complicated formula requires:
–
–
–
–
length of lists (N)
sums of lists (Sx and Sy)
dot product of the two lists (Sxy)
sums of squares of lists (Sxx and Syy)
Result is
(N*Sxy – Sx*Sy)
sqrt((N*Sxx) – (Sx)2)*(N*Syy – (Sy)2))
What Do We Need?
Functions that calculate:
–
–
–
–
length of a list
sum of a list
dot product of two lists
sum of squares of list
Assume We Have Them
Write the result calculation function
(N*Sxy – Sx*Sy)
sqrt((N*Sxx) – (Sx)2)*(N*Syy – (Sy)2))
Write the main function
–
–
–
–
N = length of lists (must be same for both)
Sx = sum of list 1st list, Sy = sum of second
Sxy = dot product of lists
Sxx = sums of squares of 1st list, Syy = ditto 2nd
Now for the Helpers
Already have the length function built in
Write the sum of a list function
Write the dot product function
– (1 2 3) * (4 5 6) = (1*4)+(2*5)+(3*6) = 32
Write the sum of squares function
– note: can use dot product function
Final Result
(defun correlation (Xs Ys) …)
(defun correlation-calc (N Sx Sy Sxy Sxx Sxy) …)
(defun sum-of-list (L) …)
(defun dot-product (Xs Ys) …)
(defun sum-of-squares (L) …)
> (correlation ‘(5 10 15) ‘(3 6 12))
0.989
Exercise
Write a function that calculates the
correlation of a list of pairs
– (correlate-pairs ‘((5 3) (10 6) (15 12))) => 0.989
– list of (X Y) pairs
Use the correlation function from last time
– (correlation ‘(5 10 15) ‘(3 6 12)) => 0.989
– only difference is the form of the data
– (write it in two lines! (hint: be lazy))
Exercise
Use the list translation programming idiom
we discussed earlier to write the rest of the
support functions for our new correlations
function
– translate list of XY pairs into a list of Xs
– translate list of XY pairs into a list of Ys
Next Time
Control over lists
– Chapter 6