Iteration

advertisement

Chapters 6 & 7

Iteration

Iteration in LISP

 LISP (unlike Prolog) allows iteration

– mapcar, remove-if(-not), count-if, find-if for special purpose iteration

 Dotimes, dolist & do allow more general iteration

– often used with side-effects

Review of Do

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

1 2 3 4 5 6 7 8 9 10

DONE

DoTimes Example

 Exponentiation function

– (power 5 3) => 125

(defun power (M N) extra form in defun just for the side effect

(setf result 1)

(dotimes (i N result) (setf result (* M result)))) loop control variable body of the loop upper bound of the loop return value done for the side effect

DoTimes Operation

(dotimes (

<body> i N result

)

) for ( i = 0; i < N ; i ++ )

<body> return result ;

(dotimes (i N res)

(setf res (* M res))) 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

 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

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

 Run loop to N+1 so we get sum 0..N

– 0 adds nothing to the sum, so that’s OK

 Alternative: (dotimes (i N (+ sum N))

)

Local

vs.

Global Variables

 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?

 Would like all the variables to be local

 LISP gives us let and let*

Let

 Let defines & initializes local variables

> (let ((v1 10) (v2 5)) (+ v1 v2))

15

> v1

ERROR: undefined variable

 (let <list-of-variable-value-pairs> <body>)

– value of <body> becomes value of let

Using Let

(defun power (M N)

(let ((result 1))

(dotimes (i N result) (setf result (* M result))))

 result now local – no complications

 Note: ((result 1))

– list of variable-value pairs

– each pair in its own list

Let with Multiple Variables

 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

 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

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

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

 In case you want to set one value based on another

> (let* ((x 5) (y (+ x 10))) (+ x y))

20

 X is already a local variable by the time let* gets to it

DoList

 DoList allows iteration over lists

– do something for each element of a list

– also usually with side-effects

 (dolist (<var> <list> <result>) <body>)

– <var> set to each element of <list> in turn

– <body> evaluated for each value

– <result> evaluated & returned

DoList Example

 (do-reverse ‘(1 2 3 4 5)) => (5 4 3 2 1)

(defun do-reverse (L)

(let ((rev ()))

(dolist (e L rev) (setf rev (cons e rev)))))

 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

(+ 11 15) => 26

=> sum => 26

Exercise

 Write the function do-intersect, to calculate the intersection of two lists using let and dolist

> (do-intersect ‘(1 3 5 7 9) ‘(3 6 9 12))

(9 3)

Solution

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

 Applications

– chapters 24 & 26

Next Time

Download