570 likes | 696 Views
CS 480/680 – Comparative Languages. Recursion and Iteration Let the entertainment begin…. No Iteration??. Yes, it’s true, there is no iteration in Scheme. So, how do we achieve simple looping constructs? Here’s a simple example from Cal-Tech:. Summing integers.
E N D
CS 480/680 – Comparative Languages Recursion and IterationLet the entertainment begin…
No Iteration?? • Yes, it’s true, there is no iteration in Scheme. So, how do we achieve simple looping constructs? Here’s a simple example from Cal-Tech: Recursion and Iteration
Summing integers • How do I compute the sum of the first N integers? Recursion and Iteration
Decomposing the sum • Sum of first N integers = • N + N-1 + N-2 + … 1 • N + ( N-1 + N-2 + … 1 ) • N + [sum of first N-1 integers] Recursion and Iteration
to Scheme • Sum of first N integers = N + [sum of first N-1 integers] • Convert to Scheme (first attempt): (define (sum-integers n) (+ n (sum-integers (- n 1)))) Recursion and Iteration
Recursion in Scheme • (define (sum-integers n) (+ n (sum-integers (- n 1)))) • sum-integers defined in terms of itself • This is a recursively defined procedure ... which is incorrect • Can you spot the error? Recursion and Iteration
Almost… • What’s wrong? (define (sum-integers n) (+ n (sum-integers (- n 1)))) • Gives us: • N + N-1 + …+ 1 + 0 + -1 + -2 + … Recursion and Iteration
Debugging • Fixing the problem: • it doesn’t stop at zero! • Revised: (define (sum-integers n) (if(= n 0) 0 (+ n (sum-integers (- n 1))))) • How does this evaluate? Recursion and Iteration
Warning • The substitution evaluation you are about to see is methodical, mechanistic, • and extremely tedious. • It will not all fit on one slide. • Don't take notes, but instead try to grasp the overall theme of the evaluation. Recursion and Iteration
Evaluating • Evaluate: (sum-integers 3) • evaluate 3 3 • evaluate sum-integers (lambda (n) (if …)) • apply (lambda (n) (if (= n 0) 0 (+ n (sum-integers (- n 1))))) to 3 (if (= 3 0) 0 (+ 3 (sum-integers (- 3 1)))) Recursion and Iteration
Evaluating… • Evaluate:(if (= 3 0) 0 (+ 3 (sum-integers (- 3 1)))) • evaluate (= 3 0) • evaluate 3 3 • evaluate 0 0 • evaluate = = • apply = to 3, 0 #f • since expression is false, • replace with false clause: (+ 3 (sum-integers (- 3 1))) • evaluate: (+ 3 (sum-integers (- 3 1))) Recursion and Iteration
Evaluating… • evaluate (+ 3 (sum-integers (- 3 1))) • evaluate 3 3 • evaluate (sum-integers (- 3 1)) • evaluate (- 3 1) ...[skip steps] … 2 • evaluate sum-integers(lambda (n) (if …)) Recursion and Iteration
Evaluating… • evaluate (+ 3(sum-integers (- 3 1))) • evaluate 3 3 • evaluate (sum-integers (- 3 1)) • evaluate (- 3 1) ...[skip steps] … 2 • evaluate sum-integers(lambda (n) (if …)) Note: now pending (+ 3 …) Recursion and Iteration
Pending (+ 3 …) Evaluating… • apply (lambda (n) (if (= n 0) 0 (+ n (sum-integers (- n 1))))) to 2 (if (= 2 0) 0 (+ 2 (sum-integers (- 2 1))) Recursion and Iteration
Pending (+ 3 …) Evaluating… • evaluate:(if (= 2 0) 0 (+ 2 (sum-integers (- 2 1))) • evaluate (= 2 0) … [skip steps] … #f • since expression is false, • replace with false clause • (+ 2 (sum-integers (- 2 1))) • evaluate: (+ 2 (sum-integers (- 2 1))) Recursion and Iteration
Pending (+ 3 …) Evaluating… • evaluate (+ 2 (sum-integers (- 2 1))) • evaluate 2 2 • evaluate (sum-integers (- 2 1)) • evaluate (- 2 1) ...[skip steps] … 1 • evaluate sum-integers(lambda (n) (if …)) • apply (lambda (n) …) to 1 • (if (= 1 0) 0 (+ 1 (sum-integers (- 1 1)))) • evaluate (= 1 0)...[skip steps] … #f Note: pending (+ 3 (+ 2 …)) Recursion and Iteration
Pending (+ 3 (+ 2 …)) Evaluating… • Evaluate (+ 1 (sum-integers (- 1 1))) • evaluate 1 1 • evaluate (sum-integers (- 1 1)) • evaluate (- 1 1) ...[skip steps] … 0 • evaluate sum-integers(lambda (n) (if …)) • apply (lambda (n) …) to 0 • (if (= 0 0) 0 (+ 1 (sum-integers (- 0 1)))) • evaluate (= 0 0) #t • result: 0 Note: pending (+ 3 (+ 2 (+ 1 0))) Recursion and Iteration
Pending (+ 3 (+ 2 (+ 1 0))) Evaluating Back to pending: • Know (sum-integers (- 1 1)) 0[prev slide] • Evaluate (+ 1 (sum-integers (- 1 1))) • evaluate 1 1 • evaluate (sum-integers (- 1 1)) 0 • evaluate + + • apply + to 1, 0 1 Note: pending (+ 3 (+ 2 1)) Recursion and Iteration
Pending (+ 3 (+ 2 1)) Evaluating Back to pending: • Know (sum-integers (- 2 1)) 1 [prev slide] • Evaluate (+ 2 (sum-integers (- 2 1))) • evaluate 2 2 • evaluate (sum-integer (- 2 1)) 1 • evaluate + + • apply + to 2, 1 3 Note: pending (+ 3 3) Recursion and Iteration
Evaluating Finish pending: • (+ 3 3) • … final result: 6 Recursion and Iteration
…Yeah!!! … Substitution model… • …works fine for recursion. • Recursive calls are well-defined. • Careful application of model shows us what they mean and how they work. Recursion and Iteration
Recursive Functions • Since there are no iterative constructs in Scheme, most of the power comes from writing recursive functions • This is fairly straightforward if you want the procedure to be global: (define factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1)))))) (factorial 5) »120 Recursion and Iteration
The trick • Must find the structure of the problem: • How can I break it down into sub-problems? • What are the base cases? Recursion and Iteration
List Processing • Suppose I want to search a list for the max value? • A standard list: • What is the base case? • What state do I need to maintain? lst 3 7 4 1 Recursion and Iteration
lst 3 7 4 1 5 2 3 9 More list processing • How about a list of X-Y pairs? • What would the list look like? • Given X, find Y: • Base case • State • Helper procedures? Recursion and Iteration
Using Recursion • Write avg.scheme • See list-position.scheme • See count_atoms.scheme • See printtype.scheme Recursion and Iteration
Mutual Recursion • Note: Scheme has built-in primitives even? and odd? (define is-even? (lambda (n) (if (= n 0) #t (is-odd? (- n 1))))) (define is-odd? (lambda (n) (if (= n 0) #f (is-even? (- n 1))))) Recursion and Iteration
Recursion and Local Definitions • Recursion gets more difficult when you want the functions to be local in scope: local-odd? is not yet defined (let ((local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1))))) (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1)))))) (list (local-even? 23) (local-odd? 23))) Can we fix this with let* ? Recursion and Iteration
letrec • letrec – the variables introduced by letrec are available in both the body and the initializations • Custom made for local recursive definitions (letrec ((local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1))))) (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1)))))) (list (local-even? 23) (local-odd? 23))) Recursion and Iteration
Recursion for loops • Instead of a for loop, this letrec uses a recursive procedure on the variable i, which starts at 10 in the procedure call. (letrec ((countdown (lambda (i) (if (= i 0) 'liftoff (begin (display i) (newline) (countdown (- i 1))))))) (countdown 10)) Recursion and Iteration
Named let • This is the same as the previous definition, but written more compactly • Named let is useful for defining and running loops ((let countdown ((i 10)) (if (= i 0) 'liftoff (begin (display i) (newline) (countdown (- i 1))))) Recursion and Iteration
Recursion and Stack Frames • What happens when we call a recursive function? • Consider the following Fibonacci function: int fib(int N) { int prev, pprev; if (N == 1) { return 0; } else if (N == 2) { return 1; } else { prev = fib(N-1); pprev = fib(N-2); return prev + pprev; } } Recursion and Iteration
Stack Frames • Each call to Fib produces a new stack frame • 1000 recursive calls = 1000 stack frames! • Inefficient relative to a for loop pprev prev N pprev prev N Recursion and Iteration
How can we fix this inefficiency? • Here’s an answer from the Cal-Tech slides: Recursion and Iteration
Example • Recall from last time: (define (sum-integers n) (if (= n 0) 0 (+ n (sum-integers (- n 1))))) Recursion and Iteration
Revisited (summarizing steps) • Evaluate: (sum-integers 3) • (if (= 3 0) 0 (+ 3 (sum-integers (- 3 1)))) • (if #f 0 (+ 3 (sum-integers (- 3 1)))) • (+ 3 (sum-integers (- 3 1))) • (+ 3 (sum-integers 2)) • (+ 3 (if (= 2 0) 0 (+ 2 (sum-integers (- 2 1))))) • (+ 3 (+ 2 (sum-integers 1))) • (+ 3 (+ 2 (if (= 1 0) 0 (+ 1 (sum-integer (- 1 1)))))) Recursion and Iteration
Revisited (summarizing steps) • (+ 3 (+ 2 (+ 1 (sum-integers 0)))) • (+ 3 (+ 2 (+ 1 (if (= 0 0) 0 …)))) • (+ 3 (+ 2 (+ 1 (if #t 0 …)))) • (+ 3 (+ 2 ( + 1 0))) • … • 6 Recursion and Iteration
Evolution of computation • (sum-integers 3) • (+ 3 (sum-integers 2)) • (+ 3 (+ 2 (sum-integers 1))) • (+ 3 (+ 2 (+ 1 (sum-integers 0)))) • (+ 3 (+ 2 (+ 1 0))) Recursion and Iteration
On input N: How many calls to sum-integers? N+1 How much work per call? (sum-integers 3) (+ 3 (sum-integers 2)) (+ 3 (+ 2 (sum-integers 1))) (+ 3 (+ 2 (+ 1 (sum-integers 0)))) (+ 3 (+ 2 (+ 1 0))) What can we say about the computation? Recursion and Iteration
This is what we call a linear recursive process Makes linear # of calls i.e. proportional to N Keeps a chain of deferred operations linear in size w.r.t. input i.e. proportional to N (sum-integers 3) (+ 3 (sum-integers 2)) (+ 3 (+ 2 (sum-integers 1))) (+ 3 (+ 2 (+ 1 (sum-integers 0)))) (+ 3 (+ 2 (+ 1 0))) Linear recursive processes • time = C1 + N*C2 Recursion and Iteration
Another strategy To sum integers… add up as we go along: • 1 2 3 4 5 6 7 … • 1 1+2 1+2+3 1+2+3+4 ... • 1 3 6 10 15 21 28 … Recursion and Iteration
Alternate definition (define (sum-int n) (sum-iter 0 n 0));; start at 0, sum is 0 (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) Evaluation of sum-int Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) (if (> 0 3) … ) (sum-iter 1 3 0) Evaluation of sum-int Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) (if (> 0 3) … ) (sum-iter 1 3 0) (if (> 1 3) … ) (sum-iter 2 3 1) Evaluation of sum-int Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) (if (> 0 3) … ) (sum-iter 1 3 0) (if (> 1 3) … ) (sum-iter 2 3 1) (if (> 2 3) … ) (sum-iter 3 3 3) Evaluation of sum-int Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) (if (> 0 3) … ) (sum-iter 1 3 0) (if (> 1 3) … ) (sum-iter 2 3 1) (if (> 2 3) … ) (sum-iter 3 3 3) (if (> 3 3) … ) (sum-iter 4 3 6) Evaluation of sum-int Recursion and Iteration
(define (sum-int n) (sum-iter 0 n 0)) (define (sum-iter current max sum) (if (> current max) sum (sum-iter (+ 1 current) max (+ current sum)))) (sum-int 3) (sum-iter 0 3 0) (if (> 0 3) … ) (sum-iter 1 3 0) (if (> 1 3) … ) (sum-iter 2 3 1) (if (> 2 3) … ) (sum-iter 3 3 3) (if (> 3 3) … ) (sum-iter 4 3 6) (if (> 4 3) … ) 6 Evaluation of sum-int Recursion and Iteration
on input N: How many calls to sum-iter? N+2 How much work per call? (sum-int 3) (sum-iter 0 3 0) (sum-iter 1 3 0) (sum-iter 2 3 1) (sum-iter 3 3 3) (sum-iter 4 3 6) 6 What can we say about the computation? Recursion and Iteration
on input N: How many calls to sum-iter? N+2 How much work per call? constant one comparison, one if, two additions, one call How many deferred operations? none (sum-int 3) (sum-iter 0 3 0) (sum-iter 1 3 0) (sum-iter 2 3 1) (sum-iter 3 3 3) (sum-iter 4 3 6) 6 What can we say about the computation? Recursion and Iteration