Function Design

Download Report

Transcript Function Design

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