meeting -*- Outline -*- * flat recursion over lists (Little Schemer ch. 2-4, EOPL 1.2.1) advertisement: this may seem to be just for lists at first, but also applies to languages (grammars), and other recursive data (like windows ...) why? recursion used extensively in grammars for programming languages matching recursion produces a "well-structured" program, that is easy to write and understand ** inductive definition of lists ------------------------------------------ INDUCTIVE DEFINITION OF LISTS def: a (list-of T) is - either - or Grammar: ------------------------------------------ ... () ... a pair, (cons v l), where v:T and l:(list-of T) ... ::= () | ( . ) ** tips (summary) warning: be systematic! I'm trying to give you another way to think; the usual imperative way (try something and debug) wastes lots of time (hours for 4 line program). There is no way you'll get the right answer quickly by tinkering and debugging. *** write examples ------------------------------------------ TIPS FOR REDUCING HOMEWORK TIME FOR RECURSIVE PROGRAMS 1. Write out your own examples if needed a. base case(s) b. related simpler example ------------------------------------------ ... (sum-squares '()) ==> 0 (sum-squares '(3 4 2)) ==> 29 (sum-squares '(4 2)) ==> 20 (sum-squares '(2)) ==> 4 *** write down the type ------------------------------------------ MORE TIPS 2. What are the types? Write it down (deftype sum-squares ------------------------------------------ ... (-> ((list-of number)) number)) *** follow the grammar ------------------------------------------ MORE TIPS 3. Use an outline that matches the grammar for the input data type. "Follow the grammar!" ::= () | ( . ) ------------------------------------------ (deftype sum-squares (-> ((list-of number)) number)) (define sum-squares (lambda (lon) (cond ((null? lon) ______) (else (_________ (sum-squares (cdr lon))))))) *** fill in by generalizing examples ------------------------------------------ MORE TIPS 4. Fill in the outline by generalizing the examples a. What's returned in the base case(s)? (sum-squares '()) ==> 0 b. How do we get the answer from - recursive call's answer, and - other information? (sum-squares '(3 4 2)) ==> 29 _______ __ lst (sum-squares lst) (sum-squares '(4 2)) ==> 20 _____ __ (cdr lst) (sum-squares (cdr lst)) ------------------------------------------ Use the related simpler example to ask how, generalize *** when debugging, work bottom up ------------------------------------------ MORE TIPS 5. When debugging, work bottom up from subexpressions (define lst '(3 4 2)) (cdr lst) (car lst) (* (car lst) (car lst)) ... If you need to use a recursive call when debugging, use the value instead (+ (car lst) (car lst) 20) ------------------------------------------ Don't try things randomly when debugging, use a strategy! ** deriving recursive programs from examples *** example ------------------------------------------ DERIVATION FROM RELATED EXAMPLES (zip '(3 4 2) '(5 9 7)) ==> ((3 5) (4 9) (2 7)) (zip '(4 2) '(9 7)) ==> ((4 9) (2 7)) (zip '() '(3 1 4 1 5 9)) ==> () (zip '(2 7 3 4) '()) ==> () ------------------------------------------ Q: What's a related simpler example for the second example? Q: What's the type? (deftype zip (-> ((list-of number) (list-of number)) (list-of-number))) Q: What are the cases? What's the outline? Q: What is the answer for the base cases? Q: How to decompose? Where is the recursion? Q: How do we get from the answer for the recursion to what we want? look at the related example, generalize. Point out: - basis - the "one step" - the "rest of the journey" - combining the one step with the rest of the journey *** trace ------------------------------------------ HOW IT WORKS (zip '(3 4 2) '(5 9 7)) = ((lambda (fsts snds) (cond ...)) '(3 4 2) '(5 9 7)) = (cond ((null? '(3 4 2)) '()) ((null? '(5 9 7)) '()) (else (cons (list (car '(3 4 2)) (car '(5 9 7))) (zip (cdr '(3 4 2)) (cdr '(5 9 7)))))) = (cons (list (car '(3 4 2)) (car '(5 9 7))) (zip (cdr '(3 4 2)) (cdr '(5 9 7)))) = (cons (list 3 5) (zip '(4 2) '(9 7))) = (cons (list 3 5) (cons (list 4 9) (zip '(2) '(7)))) = (cons (list 3 5) (cons (list 4 9) (cons (list 2 7) (zip '() '())))) = (cons (list 3 5) (cons (list 4 9) (cons (list 2 7) '()))) = (cons (list 3 5) (cons (list 4 9) '((2 7)))) = (cons (list 3 5) '((4 9) (2 7))) = '((3 5) (4 9) (2 7)) ------------------------------------------ go over the first substitution carefully, then faster *** try it ------------------------------------------ FOR YOU TO DO (xerox '(3 9 2)) ==> (3 3 9 9 2 2) (xerox '(9 2)) ==> (9 9 2 2) (xerox '()) ==> () ------------------------------------------ Q: What's a related example? (xerox '(9 2)) ==> (9 9 2 2) Q: What's the type? Q: How do you make (3 9 9 2 2) from (3 9 2) and (9 9 2 2)? Q: How do you make (3 3 9 9 2 2) from (3 9 2) and (3 9 9 2 2)? ** more complex cases *** give yourself examples to cover all cases ------------------------------------------ GIVE YOURSELF EXAMPLES TO COVER ALL CASES (insert-before 'x 'q '()) ==> () (insert-before 'x 'q '(x y z x)) ==> (q x y z x) (insert-before 'x 'q '(a x y z)) ==> (a q x y z) Type: (deftype insert-before (-> (symbol symbol (list-of symbol)) (list-of symbol))) Grammar for input data: ::= () | ( . ) Outline that matches grammar: (define insert-before (lambda (where what los) ------------------------------------------ Q: What examples are we missing? Q: Which argument has an inductively specified type? so the outline, which gives partial credit, is 2 cases, with a test for the first also in the 2nd case, will recurse on cdr if need be because that's where the grammar is recursive in the second case there are also 2 cases but those are not the context-free cases. finish writing this, by working with the examples... summary: it's the input data that determines the overall structure. *** example for you ------------------------------------------ FOR YOU TO DO (IN PAIRS) (insert-before-all 'x 'q '()) ==> () (insert-before-all 'x 'q '(x y z x)) ==> (q x y z q x) (insert-before-all 'x 'q '(a x y z x)) ==> '(a q x y z q x) Any other examples you want? What's the type? What's the structure of the code? Write it! ------------------------------------------ Q: How does this differ from insert-before?