Iteration Chapters 6 & 7
Iteration in LISP n LISP (unlike Prolog) allows iteration –mapcar, remove-if(-not), count-if, find-if for special purpose iteration n Dotimes, dolist & do allow more general iteration –often used with side-effects
Review of Do n Do takes list of local variables, stopping condition plus return expression and body > (do ((i 1 (1+ i))) ((> i 10) ‘done) (format t “~a ” i)) DONE
DoTimes Example n Exponentiation function –(power 5 3) => 125 (defun power (M N) (setf result 1) (dotimes (i N result) (setf result (* M result)))) extra form in defun just for the side effect body of the loop done for the side effect loop control variable upper bound of the loop return value
DoTimes Operation (dotimes (i N result) ) (dotimes (i N res) (setf res (* M res))) for ( i = 0; i for ( i = 0; i return result; for ( i = 0; i < N; i++) res = M * res; return res; Loop control variable is not evaluated Upper bound is evaluated before 1 st iteration Return result is evaluated after last iteration Body evaluated once per iteration
DoTimes Factorial n Loop control variable available in the loop –just like loop control in imperative languages (defun factorial (N) (setf fact 1) (dotimes (i N fact) (setf fact (* (1+ i) fact)))) Need to add 1 to i, because i runs from 0 to N–1, not 1 to N
Exercise n Write a function using dotimes to calculate the sum of the numbers from 1 to N –can you do it without adding 1 to i each time?
Solution (defun sum-to-N (N) (setf sum 0) (dotimes (i (1+ N) sum) (setf sum (+ sum i)))) n Run loop to N+1 so we get sum 0..N –0 adds nothing to the sum, so that’s OK n Alternative: (dotimes (i N (+ sum N)) …)
Local vs. Global Variables n Functions above use global variables –not good – what if someone was using them already? –what if one of the functions called uses the same global variable? n Would like all the variables to be local n LISP gives us let and let*
Let n Let defines & initializes local variables > (let ((v1 10) (v2 5)) (+ v1 v2)) 15 > v1 ERROR: undefined variable n (let ) –value of becomes value of let
Using Let (defun power (M N) (let ((result 1)) (dotimes (i N result) (setf result (* M result)))) n result now local – no complications n Note: ((result 1)) –list of variable-value pairs –each pair in its own list
Let with Multiple Variables n Can use as many as you like (defun correlation (X Y) (let ((N (length X)) (Sx (sum-list X)) (Sy (sum-list Y)) (Sxy (dot-product X Y)) (Sxx (sum-of-squares X)) (Syy (sum-of-squares Y))) (/ (– (* N Sxy) (* Sx Sy)) (* …)))))
Exercise n Rewrite factorial and sum-to-N using lets (defun factorial (N) (setf fact 1) (dotimes (i N fact) (setf fact (* (+ i 1) fact)))) (defun sum-to-N (N) (setf sum 0) (dotimes (i (+ N 1) sum) (setf sum (+ sum i))))
Let Works in Parallel n All assignments are done “at the same time” –can’t use the value of one to set another > (let ((x 5) (y (+ x 10))) …) ERROR – unbound variable X n Won’t get an error if x is defined –you’ll just get the other value of x –(let ((x 5) (y (+ x 10))) (+ x y)) => 796 (!!!) “other” X was 781
Let* Works in Serial n In case you want to set one value based on another > (let* ((x 5) (y (+ x 10))) (+ x y)) 20 n X is already a local variable by the time let* gets to it
DoList n DoList allows iteration over lists –do something for each element of a list –also usually with side-effects n (dolist ( ) ) – set to each element of in turn – evaluated for each value – evaluated & returned
DoList Example n (do-reverse ‘( )) => ( ) (defun do-reverse (L) (let ((rev ())) (dolist (e L rev) (setf rev (cons e rev))))) n Elements added to front of rev –rev = (), (cons 1 rev) => (1) –rev = (1), (cons 2 rev) => (2 1)
Sum-List Using DoList > (defun sum-list (L) (let ((sum 0)) (dolist (e L sum) (setf sum (+ sum e))))) > (sum-list ‘(4 7 15)) sum 0 e 4, sum (+ 0 4) => 4 e 7, sum (+ 4 7) => 11 e 15, sum ( ) => 26 => sum => 26
Exercise n Write the function do-intersect, to calculate the intersection of two lists using let and dolist > (do-intersect ‘( ) ‘( )) (9 3)
Solution n Iterate thru first list –if current element is in second list, add it to the intersection –intersection should have started as empty (defun do-intersection (L1 L2) (let ((inter ())) (dolist (e L1 inter) (when (member e L2) (push e inter)))))
Next Time n Applications –chapters 24 & 26