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
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)
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.
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 f n
;; (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
;; (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
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
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
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
Add one to each element of a list plus1List(L) if (L == nil) return nil; variables not necessary else var newFirst
first(L) + 1; var newRest
plus1List(rest(L)); return cons(newFirst, newRest);
Add one to each element of a list plus1List(L) if (L == nil) else return nil; replace conditional command with conditional expression return cons(first(L) + 1, plus1List(rest(L)));
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)));
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)))))
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
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
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))))
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
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))
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
Given a number and the mean, return a number (its deviation)
– their difference, squared
– use expt for squaring (expt x 2) = x 2
(defun calculate-deviation (Value Mean)
(expt (– Value Mean) 2))
(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)))
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)
(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))
(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))
(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))
(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
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
(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
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))
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))
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
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 ))
Functions that calculate:
– length of a list
– sum of a list
– dot product of two lists
– sum of squares of list
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 1 st list, Sy = sum of second
– Sxy = dot product of lists
– Sxx = sums of squares of 1 st list, Syy = ditto 2 nd
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
(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
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) )
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
Control over lists
– Chapter 6