Lecture 12
Iterative Recursion - A Slightly Different Flavour
Basic template for recursion
(define function
(lambda (args)� (if easy-case?� solve-easy-case� (fix-solution� (function simplified))))
Special kinds of recursion
(define function
(lambda (args)� (if easy-case?� solve-easy-case� (fix-solution� (function simplified))))
Iterative recursion
Summing a list using recursion
We can add up the elements of a list by
;; sum-list:
;; (listof number) -> number
;; Total of elements of a list
(define sum-list
(lambda (sum-list)
(if (empty? list)
0
(+ (first list)
(sum-list (rest list))))))
Is that the only way to do it?
;; sum-list:
;; (listof number) -> number
;; Total of elements of a list
(define sum-list
(lambda (sum-list)
(if (empty? list)
0
(+ (first list)
(sum-list (rest list))))))
Keeping a partial sum (an accumulator)
;; sum-list:
;; (listof number) -> number
;; Sum of all numbers in list
(define sum-list
(lambda (a-list)
(if (empty? a-list)
0
(+ (first a-list)
(sum-list (rest a-list))))))
;; sum-list:
;; (listof number) number -> number
;; Sum of all numbers in list plus partial-sum
(define sum-list
(lambda (a-list partial-sum)
(if (empty? a-list)
partial-sum
(sum-list (rest a-list)
(+ (first a-list)
partial-sum)))))
Why it matters
Adding last:
'())))))
Adding first:
Holding + until last requires more stack space to keep track pending operations.
Iteration and recursion
How do we write foldl?
;; sum-list:
;; (listof number) number -> number
;; Sum of all numbers in list plus partial-sum
(define sum-list
(lambda (a-list partial-sum)
(if (empty? a-list)
partial-sum
(sum-list (rest a-list)
(+ (first a-list)
partial-sum)))))
How do we write foldl?
;; foldl:
;; (X X -> X) X (listof X) -> X
;; Uses func to collapse all elements of list
;; plus partial-sum
(define foldl
(lambda (func partial-result a-list)
(if (empty? a-list)
partial-result
(foldl func
(func (first a-list)
partial-result)
(rest a-list))))
In the video there's a typo on this slide (extra paren) it's been corrected here.
Helper procedures
Example
;; length: (listof X) -> number
;; Number of elements in list
Example
;; length: (listof X) -> number
;; Number of elements in list
(define length
(lambda (a-list)
(length-loop a-list 0)))
;; length-loop: (listof X) number -> number
;; Number of elements in list plus length-so-far
(define length-loop
(lambda (list-remaining length-so-far)
(if (empty? list-remaining)
length-so-far
(length-loop (rest list-remaining)
(+ length-so-far 1)))))
Execution under the substitution model
0
(length-loop (rest '(1 2 3))
(+ 0 1)))
0
(length-loop (rest '(1 2 3))
(+ 0 1)))
(+ 0 1)))
1
(length-loop (rest '(2 3))
(+ 1 1)))
1
(length-loop (rest '(2 3))
(+ 1 1)))
(+ 1 1)))
2
(length-loop (rest '(3)) (+ 2 1)))
2
(length-loop (rest '(3)) (+ 2 1)))
Execution under the substitution model
3
(length-loop (rest '())
(+ 3 1)))
3
(length-loop (rest '())
(+ 3 1)))
Making it prettier
;; length: (listof X) -> number
;; Number of elements in list
(define my-length
(lambda (a-list)
;; loop: (listof X) number -> number
;; Number of elements in list plus length-so-far
(local [(define loop
(lambda (a-list length-so-far)
(if (empty? a-list)
length-so-far
(loop (rest a-list)
(+ length-so-far 1)))))]
(loop a-list 0))))
Iterative Recursion
(define (help args … accum)
(if easy-case?� accum� (help args …
(updater accum …))))
(define (func args …) � (help args … start-accum))
Tree recursion
Basic template for recursion
(define function
(lambda (args)� (if easy-case?� solve-easy-case� (fix-solution� (function simplified))))
Basic template for recursion
(define (func args …) � (if easy-case?� solve-easy-case� (combine (func one-part)� (func other-part)))))
How google sums a list
(define sum-list
(lambda (a-list)
(if (list-fits-on-one-processor? a-list)
(add-it-up a-list)
(+ (sum-list (first-half a-list))
(sum-list (second-half a-list)))))
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list:
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list: + Sum this list:
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list: + Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list: + Sum this list: Sum this list: + Sum this list:
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list: + Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10 + 26 42 + 58
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sum this list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
36 + 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10 + 26 42 + 58
Parallel summation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
136
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
36 + 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10 + 26 42 + 58
Optional reading
Chapter 1 of Abelson and Sussman
Basic template for recursion
(define function
(lambda (args)� (if easy-case?� solve-easy-case� (fix-solution� (function simplified))))
Iterative Recursion
(define (func args …) � (if easy-case?� solve-easy-case� (combine (func one-part)� (func other-part)))))
Tree Recursion
(define (help args … accum)
(if easy-case?� accum� (help args …
(updater accum …))))
(define (func args …) � (help args … start-accum))
Sussman-form definitions
From Tutorial 3
This is a good time to mention Sussman-form definitions
(define (function-name inputs …)�output)
Got a lot of cases?
From Tutorial 4
That's what cond is for!
(if test R1 R2) ; if test is true, then R1 otherwise R2
(if (> x 5) "big" "small")
(cond [test-1 R1] ; if test-1 is true, then R1
[test-2 R2] ; otherwise if test-2 is true, then R2
…
[test-n Rn]); otherwise if test-n is true, then Rn
(cond [(> x 5) "big"] ; if x > 5, then "big"
[(= x 5) "medium"] ; otherwise if x = 5, "medium"
[else "small"]) ; otherwise "small"