Class 09: Recursion practice, how recursive programs work Recall the - - PowerPoint PPT Presentation
Class 09: Recursion practice, how recursive programs work Recall the - - PowerPoint PPT Presentation
Class 09: Recursion practice, how recursive programs work Recall the list-length procedure (define (list-length alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (list-length (rest alon)))])) Why does it correctly compute the length of any
Recall the list-length procedure
(define (list-length alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (list-length (rest alon)))]))
- Why does it correctly compute the length of any list?
- Does it work for lists of length zero?
- How many of those are there?
- Does it work for lists of length 1?
- Yes…
- Provided that the recursive call computing the length of the rest of the list works
- The rest of the list has length 0, so its length does get computed correctly
- Same argument for length 2, 3, 4, …
Recursion diagrams and correct procedures
- Recursion diagrams prepare for this logical analysis to
work!
- They ensure that the answer for length-zero lists is
correct
- They ensure that if the answer for length-(k-1) lists is
correct, then the answer for length-k lists will be as well!
Does it work at a mechanical level?
- Do the rules of evaluation lead to the results you
expect?
- Yes (no surprise!)
- We’ll see this by computing the length of a length-one
list, using the rules.
Warmup: cleaning up Boolean expressions
A recursion problem
- contains17? takes as input an int list, and returns
true if one of the items is the number 17, and false if the list does not contain a 17.
- The type-signature is contains17?: (int list) - >
bool
- With your neighbor, draw recursion diagrams for three
cases:
- (cons 13 (cons 4 empty))
- (cons 17 empty)
- (cons 1 (cons 17 empty))
OI: (cons 13 (cons 4 empty)) RI: (cons 4 empty) RO: false OO: false
OI: (cons 17 empty) RI: empty RO: false OO: true
OI: (cons 1 (cons 17 empty)) RI: (cons 17 empty) RO: true OO: true
OI: (cons 1 (cons 17 empty)) RI: (cons 17 empty) RO: true
If RO is true, OO is true If RO is false, but (first OO) is 17, then OO is true Otherwise OO is false
OO: true
Code
(define (contains17? aloi) (cond [(empty? aloi) false] [(cons? aloi) (if (contains17? (rest aloi)) true (if (= 17 (first aloi)) true false))]))
Code
(define (contains17? aloi) (cond [(empty? aloi) false] [(cons? aloi) (or (contains17? (rest aloi)) (if (= 17 (first aloi)) true false))]))
Code
(define (contains17? aloi) (cond [(empty? aloi) false] [(cons? aloi) (or (contains17? (rest aloi)) (if (= 17 (first aloi)) true false))]))
Code (better)
(define (contains17? aloi) (cond [(empty? aloi) false] [(cons? aloi) (or (contains17? (rest aloi)) (= 17 (first aloi))]))
Code (even better)
(define (contains17? aloi) (cond [(empty? aloi) false] [(cons? aloi) (or (= 17 (first aloi)) (contains17? (rest aloi))]))
Evaluation practice
(already done previously, but left here for reference!)
Color coding
- Values are in green
- Environment is a sequence of purple boxes; TLE
shorthand shows just + and – as builtin procs.
(skip to slide 42)
(+ (- 3 4) (+ 2 5)) A B C A: B: C: Value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: C: Value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: C: Value:
- B: (- 3 4)
D E F D: E: F: value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: C: Value:
- B: (- 3 4)
D E F D: builtin- E: F: value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: C: Value:
- B: (- 3 4)
D E F D: builtin- E: 3 F: 4 value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: C: Value:
- B: (- 3 4)
D E F D: builtin- E: 3 F: 4 value: -1
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4)
D E F D: builtin- E: 3 F: 4 value: -1
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: E: 3 | H: F: 4 | J: value: -1 | value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: F: 4 | J: value: -1 | value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: 2 F: 4 | J: value: -1 | value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: 2 F: 4 | J: 5 value: -1 | value:
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: 2 F: 4 | J: 5 value: -1 | value: 7
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: 7 Value:
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: 2 F: 4 | J: 5 value: -1 | value: 7
+ builtin+
- builtin-
(+ (- 3 4) (+ 2 5)) A B C A: builtin+ B: -1 C: 7 Value: 6
- B: (- 3 4) | C: (+ 2 5)
D E F | G H J D: builtin- | G: builtin+ E: 3 | H: 2 F: 4 | J: 5 value: -1 | value: 7
+ builtin+
- builtin-
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: C: Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: E: 1 | H: | | |
+ builtin+
- builtin-
f closure{(x, (+ x 1))
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: C: Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: E: 1 | H: Bind x -> 1; evaluate | (+ x 1) | | | |
+ builtin+
- builtin-
x 1
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: C: Value:
- B: (f 1) | J: (+ x 1)
D E | K L M D: closure(x, (+ x 1))| K: builtin+ E: 1 | L: 1 Bind x -> 1; evaluate | M: 1 J: (+ x 1) | Value: 2 Value: | |
+ builtin+
- builtin-
x 1
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: C: Value:
- B: (f 1) | J: (+ x 1)
D E | K L M D: closure(x, (+ x 1))| K: builtin+ E: 1 | L: 1 Bind x -> 1; evaluate | M: 1 J: (+ x 1) | Value: 2 Value: 2 | |
+ builtin+
- builtin-
x 1
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: C: Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: E: 1 | H: Bind x -> 1; evaluate | (+ x 1) | value: 2 | Drop the new binding |
+ builtin+
- builtin-
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: 2 C: Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: closure(x, (+ x 1)) E: 1 | H: 3 Bind x -> 1; evaluate | (+ x 1) | value: 2 | Drop the new binding |
+ builtin+
- builtin-
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: 2 C: Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: closure(x, (+ x 1)) E: 1 | H: 3 Bind x -> 1; evaluate | Bind x -> 3; evaluate (+ x 1) | (+ x 1) value: 2 | value: 4 Drop the new binding | Drop the new binding
+ builtin+
- builtin-
x 3
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: 2 C: 4 Value:
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: closure(x, (+ x 1)) E: 1 | H: 3 Bind x -> 1; evaluate | Bind x -> 3; evaluate (+ x 1) | (+ x 1) value: 2 | value: 4 Drop the new binding | Drop the new binding
+ builtin+
- builtin-
(define (f x) (+ x 1)) (+ (f 1) (f 3)) A B C A: builtin+ B: 2 C: 4 Value: 6
- B: (f 1) | C: (f 3)
D E | G H D: closure(x, (+ x 1))| G: closure(x, (+ x 1)) E: 1 | H: 3 Bind x -> 1; evaluate | Bind x -> 3; evaluate (+ x 1) | (+ x 1) value: 2 | value: 4 Drop the new binding | Drop the new binding
+ builtin+
- builtin-
(define (f x) (+ x 1)) (f 3)
Formal argument(s)
3
Actual argument(s)
- During evaluation of a user-defjned procedure, we “temporarily
bind formals to actuals”
T wo examples for len
(len empty) (len (cons 1 empty))
(define (len alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (len (rest alon)))])) (len empty) A B A: closure(alon, (cond …)) B: empty-value Bind alon -> empty-value Evaluate the body.
+ builtin+
- builtin-
len closure(alon, …) alon empty- value
Bind alon -> empty-value Evaluate: (cond P1: [(empty? alon) 0] P2: [(cons? alon) (+ 1 (len (rest alon)))])) P1: condition: (empty? alon) A B A: builtin:empty? B: empty-value [from extension to TLE] value: true
+ builtin+
- builtin-
len closure(alon, …) n alon empty- value
(define (len alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (len (rest alon)))])) (len empty) A B A: closure(alon, (cond …)) B: empty-value Bind alon -> empty-value Evaluate the body. => 0
+ builtin+
- builtin-
len closure(alon, …) alon empty- value
(define (len alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (len (rest alon)))])) (len empty) A B A: closure(alon, (cond …)) B: empty-value Bind alon -> empty-value Evaluate the body. => 0 Remove the extra binding(s)
+ builtin+
- builtin-
len closure(alon, …) alon empty- value
(define (len alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (len (rest alon)))])) (len (cons 1 empty)) A B A: closure(alon, (cond …)) B: (cons 1 empty-value) Bind alon -> (cons 1 empty-value) Evaluate the body.
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty-value)
Bind alon -> (cons 1 empty) Evaluate: (cond P1: [(empty? alon) 0] P2: [(cons? alon) (+ 1 (len (rest alon)))])) P1: condition: (empty? alon) A B A: builtin:empty? B: (cons 1 empty)[from extension to TLE] value: false P2: condition: (cons? alon) A B A: builtin:cons? B: (cons 1 empty) [from TLE extension] value: true Cond-expression: evaluate (+ 1 (len (rest alon))) Value: ???
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty-value)
evaluate (+ 1 (len (rest alon))) A B C A: builtin:+ B: 1 C: Value:
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty-value)
evaluate (+ 1 (len (rest alon))) A B C A: builtin:+ B: 1 C: Value:
- (len (rest alon))
D E D: closure(alon, ...) E: empty-value [Why?] Value: 0 (see prev. slides!)
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty- value) + builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty- value) alon empty-value
Bind alon -> empty-value Evaluate: (cond P1: [(empty? alon) 0] P2: [(cons? alon) (+ 1 (len (rest alon)))])) P1: condition: (empty? alon) A B A: builtin:empty? B: empty-value [from extension to TLE] value: true ...
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty- value) alon empty- value
evaluate (+ 1 (len (rest alon))) A B C A: builtin:+ B: 1 C: 0 Value: 1
- (len (rest alon))
D E D: closure(alon, ...) E: empty-value Value: 0 (see prev. slides!)
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty-value) + builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty- value) alon empty-value
(define (len alon) (cond [(empty? alon) 0] [(cons? alon) (+ 1 (len (rest alon)))])) (len (cons 1 empty)) A B A: closure(alon, (cond …)) B: (cons 1 empty) Bind alon -> (cons 1 empty) Evaluate the body. (We got 1) Remove the temporary bindings Value: 1 (yay!)
+ builtin+
- builtin-
len closure(alon, …) alon (cons 1 empty-value)
New topic: operation counting
- T
- measure whether a procedure we write is “fast” or
”slow”
- Look at how it performs as the size of the input grows
- For us: ”size” is almost always “the length of the input list”
- Use a mathematical thing called a “recurrence relation” to
express this
- “Solve” the recurrence to get a more compact and
understandable answer
- Answers will use the idea of one function being
“eventually greater than” another
- Answers will not be perfect!
- ….but they’ll be good enough to tell us the information we
almost always need
“Operations”
- Binding a name to a value
- Looking up the value associated to a name
- Computing the value of a bool, number, or string
- Evaluating cons, fjrst, rest, empty, empty?, cons?, =, >,
<, …
- Apply “or” or “and” to two items
- Arithmetic operations, all the builtins we’ve seen so far
- T
esting whether a Boolean is T/F