CS 227 Lecture -*- Outline -*- focus: the main new thing is iteration. * Numerical Recursion and Iteration (4.5) Can also use recursion on numbers using the recursive structure of the naturals or the recursive structure of various numeric function definitions. ** Examples *** factorial **** fully recursive ------------ FACTORIAL (fact 0) = 1 (fact 1) = 1*1 = 1 (fact 2) = 2*1*1 = 2 (fact 3) = 3*2*1 = 6 (fact 4) = 4*3*2*1 = 24 ------------- note how can break this down using n and (fact (sub1 n))... 4 * 3*2*1 = 6 thus get: ------------- recursive definition: (fact 0) = 1 (fact n) = (* n (fact (sub1 n))) for n >= 1 ------------ can translate the recursive definition into a program. ------------ FULLY RECURSIVE FACTORIAL PROCEDURE (define fact ; TYPE: (-> (natural) natural) (lambda (n) (if (zero? n) 1 (* n (fact (sub1 n)))))) ------------ note the "pending computation" of (* n ...) --------------- WRITE THE ANSWER TABLE FOR (fact 4) answer-1: (* 4 (answer-2)) = --------------- Have them construct the answer table for (fact 4) ANSWER TABLE (fact 4) answer-1: (* 4 (answer-2)) = answer-2: (fact 3) = (* 3 answer-3) = answer-3: (fact 2) = (* 2 answer-4) = answer-4: (fact 1) = (* 1 answer-5) = answer-5: (fact 0) = 1 Do backward substitution to get answer-1 a characteristic of full recursion Another way to summarize ------------ TRACE OF FULLY RECURSIVE FACTORIAL (fact 4) = (* 4 (fact 3)) = (* 4 (* 3 (fact 2))) = (* 4 (* 3 (* 2 (fact 1)))) = (* 4 (* 3 (* 2 (* 1 (fact 0))))) = (* 4 (* 3 (* 2 (* 1 1)))) = (* 4 (* 3 (* 2 1))) = (* 4 (* 3 2)) = (* 4 6) = 24 ------------ **** iterative this isn't the only way to do factorial. We could compute it the other way around... (* 1 (* 2 (* 3 (* 4 1)))) that is we'd like to have no pending computations. To do this we need to get the * inside the recursive call, meaning it should happen before the call One way to do that is to use an accumulator... that is, we'd like to compute from the other end Need to have (fact 0) return 1, and so returning acc means that we need to start acc at 1. EMPHASIS: designing this sequence is how you design the iteration!!! for (fact 4) int acc 4 1 acc * 4 gives 3 4 acc * 3 gives 2 12 acc * 2 gives 1 24 acc * 1 gives 0 24 So we'll start the accumulator off at 1, and at each step multiply by the number. Note that in one step of this process we reduce the number by 1, and increase the accumulator so that (* acc int) = (fact n) We use the initial acc as the initial value of the accumulator ------------ ITERATIVE FACTORIAL PROCEDURE (define fact2 ; TYPE: (-> (natural) natural) (lambda (n) (fact-it n 1))) (define fact-it ; TYPE: (-> (natural natural) natural) (lambda (int acc) (if (zero? int) acc (fact-it (sub1 int) (* acc int))))) ------------ note, there are no pending computations at the recursive call Note how this is like a loop, with simultaneous assignment... (for those who have used other languages) the way to get a variable is to add an extra parameter. The trick is that the accumulator converts pending computations of the recursive process into computations and partial (accumulated) answers. To do this, have to give the accumulator an initial value. ------------ TRACE OF ITERATIVE FACTORIAL (fact 4) = (fact-it 4 1) = (fact-it 3 4) = (fact-it 2 12) = (fact-it 1 24) = (fact-it 0 24) = 24 ------------ note the different shape. adding an accumulator is a general technique for turning recursion into iteration, but is not necessary for iteration: Another way to do iterative factorial (different sequence) for (fact 4) acc n int 1 2 4 2 3 4 6 4 4 24 5 4 But how will we know to stop at 24? will have to pass the int as another argument. compare that to 4, stop when (> n int) What happens to get from one step to the next? acc gets (* acc n) n gets (add1 n) int stays the same What are the initial values of acc, n, and int? 1 2 and the argument (define fact3 ; TYPE: (-> (natural) natural) (lambda (k) (fact-it3 1 2 k))) (define fact-it3 ; TYPE: (-> (natural natural) natural) (lambda (acc n int) (if (> n int) acc (fact-it3 (* acc n) (add1 n) int)))) *** convergence ----------------- EQUILIBRIUM TEST FROM CHAOS PROBLEM (define logistic-diff ; TYPE: (-> (number number) number) (lambda (r x) (* r x (- 1 x)))) (define reaches-equilibrium? ; TYPE: (-> (natural number number) ; boolean) (lambda (max-iter r x) (if (zero? max-iter) #f (if (= x (logistic-diff r x)) #t (reaches-equilibrium? (sub1 max-iter) r (logistic-diff r x)))))) ----------------- They should see that formals r and x are needed to make sense, they are not introduced as accumulators. I programmed this using and, or, but clearer with if... Yet this is iterative! no pending computations on the recursive call ----------------- TRACE OF REACHES-EQUILIBRIUM? (reaches-equilibrium? 100 1.0 0.5) = (reaches-equilibrium? 99 1.0 0.25) = (reaches-equilibrium? 98 1.0 .1875) = (reaches-equilibrium? 97 1.0 .15234375) = (reaches-equilibrium? 96 1.0 .12913513) ... ----------------- note the absence of pending computations. This is iterative, but no accumulator. Other examples: last-item (program 2.2) member? (program 2.3) equal-lists? ** Terms Recall that a process is a series of computational steps. --------------- TERMS def: A process is fully recursive if it has computations pending when it makes a recursive call. ---------------- like the first factorial so specifies use of something like an answer table and backward substitution. ------------- def: An process is iterative if it does NOT have computations pending when it makes any recursive call. ------------- ------------- def: a procedure is fully recursive iff it specifies a fully recursive process. def: a procedure is iterative iff it specifies an iterative process. ------------- Scheme implements iterative procedures with iterative processes, even if recursion is used to specify the iteration. Other programming languages (e.g., C/C++) use recursive processes to implement iterative procedures that use recursion. - beware. ** speed The main reasons for using iteration are speed control over result (not passed back through pending computations). We'll see a very convincing example of speed in the next section