Recursion and Iteration Let the entertainment begin…
description
Transcript of Recursion and Iteration Let the entertainment begin…
Recursion and IterationRecursion and IterationLet the entertainment begin…Let the entertainment begin…
CS 480/680 – Comparative LanguagesCS 480/680 – Comparative Languages
Recursion and Iteration 2
No Iteration??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 3
Summing integersSumming integers How do I compute the sum of the first N
integers?
Recursion and Iteration 4
Decomposing the sumDecomposing 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 5
to Schemeto 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 6
Recursion in SchemeRecursion 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 7
Almost…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 8
DebuggingDebugging
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 9
WarningWarning
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 10
EvaluatingEvaluating
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 11
Evaluating…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 12
Evaluating…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 13
Evaluating…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 14
Evaluating…Evaluating…
apply (lambda (n) (if (= n 0)
0
(+ n (sum-integers (- n 1))))) to 2
(if (= 2 0) 0 (+ 2 (sum-integers (- 2 1)))
Pending (+ 3 …)
Recursion and Iteration 15
Evaluating…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)))
Pending (+ 3 …)
Recursion and Iteration 16
Evaluating…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
Pending (+ 3 …)
Note: pending (+ 3 (+ 2 …))
Recursion and Iteration 17
Evaluating…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
Pending (+ 3 (+ 2 …))
Note: pending (+ 3 (+ 2 (+ 1 0)))
Recursion and Iteration 18
EvaluatingEvaluating
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
Pending (+ 3 (+ 2 (+ 1 0)))
Note: pending (+ 3 (+ 2 1))
Recursion and Iteration 19
EvaluatingEvaluating
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
Pending (+ 3 (+ 2 1))
Note: pending (+ 3 3)
Recursion and Iteration 20
EvaluatingEvaluatingFinish pending: (+ 3 3) … final result: 6
Recursion and Iteration 21
……Yeah!!! …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 22
Recursive FunctionsRecursive 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 23
The trickThe 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 24
List ProcessingList 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?
3 7 4 1
lst
Recursion and Iteration 25
More list processingMore 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?
3 7 4 1
lst
5 2 3 9
Recursion and Iteration 26
Using RecursionUsing Recursion Write avg.scheme See list-position.scheme See count_atoms.scheme See printtype.scheme
Recursion and Iteration 27
Mutual RecursionMutual 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 28
Recursion and Local DefinitionsRecursion and Local Definitions Recursion gets more difficult when you want
the functions to be local in scope:
(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)))
local-odd? is not yet definedlocal-odd? is not yet defined
Can we fix this with let* ?Can we fix this with let* ?
Recursion and Iteration 29
letrecletrec 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 30
Recursion for loopsRecursion 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 31
Named Named letlet
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 32
Recursion and Stack FramesRecursion 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 33
Stack FramesStack Frames Each call to Fib
produces a new stack frame
1000 recursive calls = 1000 stack frames!
Inefficient relative to a for loop
Nprev pprev
Nprev pprev
Recursion and Iteration 34
How can we fix this inefficiency?
Here’s an answer from the Cal-Tech slides:
Recursion and Iteration 35
ExampleExample
Recall from last time:
(define (sum-integers n)
(if (= n 0)
0
(+ n (sum-integers (- n 1)))))
Recursion and Iteration 36
Revisited (summarizing steps)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 37
Revisited (summarizing steps)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 38
Evolution of computationEvolution 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 39
What can we say about the What can we say about the computation?computation?
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)))
Recursion and Iteration 40
Linear recursive processesLinear recursive processes
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)))
time = C1 + N*C2
Recursion and Iteration 41
Another strategyAnother strategyTo 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 42
Alternate definitionAlternate 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 43
Evaluation of Evaluation of sum-intsum-int
(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)
Recursion and Iteration 44
Evaluation of Evaluation of sum-intsum-int
(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)
Recursion and Iteration 45
Evaluation of Evaluation of sum-intsum-int
(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)
Recursion and Iteration 46
Evaluation of Evaluation of sum-intsum-int
(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)
Recursion and Iteration 47
Evaluation of Evaluation of sum-intsum-int
(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)
Recursion and Iteration 48
Evaluation of Evaluation of sum-intsum-int
(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
Recursion and Iteration 49
What can we say about the What can we say about the computation?computation?
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
Recursion and Iteration 50
What can we say about the What can we say about the computation?computation?
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
Recursion and Iteration 51
What’s different about these What’s different about these computations?computations?
(sum-integers 3)
(+ 3 (sum-integers 2))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 0)))
(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)
Old New
Recursion and Iteration 52
Linear iterative processesLinear iterative processes
This is what we call a linear iterative process
Makes linear # calls State of computation kept
in a constant # of state variables• state does not grow with
problem size
• requires a constant amount of storage space
• (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
time = C1 + N*C2
Recursion and Iteration 53
Linear recursive vs linear iterativeLinear recursive vs linear iterative
Both require computational time which is linear in size of input
L.R. process requires space that is also linear in size of input• why?
L.I. process requires constant space• not proportional to size of input• more space-efficient than L.R. process
Recursion and Iteration 54
Linear recursive vs linear iterativeLinear recursive vs linear iterative
Why not always use linear iterative instead of linear recursive algorithm?• often the case in practice
Recursive algorithm sometimes much easier to write• and to prove correct
Sometimes space efficiency not the limiting factor
Recursion and Iteration 55
Tail-call eliminationTail-call elimination
Countdown uses only tail-recursion• Each call to countdown either does not call itself
again, or does it as the very last thing done
Scheme recognizes tail recursion and converts it to an iterative (loop) construct internally
((let countdown ((i 10)) (if (= i 0) 'liftoff (begin (display i) (newline) (countdown (- i 1)))))
Recursion and Iteration 56
Mapping a procedure across a listMapping a procedure across a list
(map add2 '(1 2 3))» (3 4 5)
(map cons '(1 2 3) '(10 20 30))» ((1 . 10) (2 . 20) (3 . 30))
(map + '(1 2 3) '(10 20 30))» (11 22 33)
Recursion and Iteration 57
ExercisesExercises Include error checking into avg.scheme
• Divide by zero error• Non-numeric list items
Write a scheme function that accepts a single numeric argument and returns all numbers less than 10 that the argument is divisible by
Factor.scheme – described in class Write a scheme function that returns the first n
Fibonacci numbers as a list (n is an argument)