Com S 342 meeting -*- Outline -*- * pairs and lists ** pairs (p. 85) *** box and pointer notation for pairs car cdr (cons 1 2) --> [ * | *-]--> 2 | v 1 *** representing sequences, lists (2.2.1) show box and pointer diagram for (cons 0 (cons 1 (cons 2 nil))) discuss list primitive: (list 0 1 2) = (cons 0 (cons 1 (cons 2 nil))) write a class Cons in Java with methods car and cdr as a semantics put this in the library ** lists *** operations on lists (p. 101 and following) --------------------------------------------------------- LISTS A (list T) is either nil or (cons x l), where x: T and l:(list T) Operations: cons : (-> (T (list T)) (list T)) pair? : (-> (object) boolean) car : (-> ((list T)) T) cdr : (-> ((list T)) (list T)) nil : (list T) null? : (-> (object) boolean) list : (-> (T ...) (list T)) list? : (-> (object) boolean) --------------------------------------------------------- also talk about how lists are displayed (cons 1 (cons 7 (cons 2 (cons 1 nil)))) ==> (1 7 2 1) nil ==> () improper lists, i.e., pairs print with dots (cons 3 4) ==> (3 . 4) (cons 4 (cons 2 3)) ==> (4 2 . 3) *** flat recursion over lists (an expansion of 2.2.1) 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. ------------------------------------------ TIPS FOR REDUCING HOMEWORK TIME FOR RECURSIVE PROGRAMS 1. What is the type? Write it down (define (add-n n items) ;; TYPE: (-> (number (list number)) (list number)) 2. Use an outline that matches the grammar for the input data type. ::= nil | ( . ) (if (null? items) _____ (______ (_____ (car items)) (add-n ______ (cdr items))))) --------------------------------------------------------- --------------------------------------------------------- TIPS CONTINUED 3. Write out your own examples if needed a. base case(s) b. non-base case and related simpler example (add-n 3 nil) = nil (add-n 4 (cons 5 (cons 7 (cons 2 nil)))) ==> (9 11 6) (add-n 4 (cons 7 (cons 2 nil))) ==> (11 6) 4. How do we get from recursion's answer to the first answer? Generalize to find what to do for the one step and how to combine that to form the "rest of the journey" 5. Recurse for each helping procedure. --------------------------------------------------------- A more complex example: (subst-all 5 7 (cons 2 (cons 7 (cons 1 (cons 7 (cons 3 nil)))))) ==> (2 5 1 5 3) Have students do: subst-first (subst-first 5 7 (cons 2 (cons 7 (cons 1 (cons 7 (cons 3 nil)))))) ==> (2 5 1 7 3) delete-first (delete-first 7 (cons 2 (cons 7 (cons 1 (cons 7 (cons 3 nil)))))) ==> (2 1 7 3) delete-all (delete-all 7 (cons 2 (cons 7 (cons 1 (cons 7 (cons 3 nil)))))) ==> (2 1 3) list-ref (list-ref (list 3.14 2.73 1.414) 0) = 3.14 (list-ref (cons 3.14 (cons 2.73 (cons 1.414 nil))) 2) = 1.414 (list-ref (cons 2.73 (cons 1.414 nil)) 1) = 1.414 length (length nil) = 0 (length (list 1 2 3 4)) = 4 (length (cons 2 (cons 3 (cons 4 nil)))) = 3 *** tail recursion on lists do length with tail recursion *** capturing common patterns as higher-order procedures **** mapping (p. 105) ------------------------------------------ MAPPING (p. 105) (define (add-n n items) ;; TYPE: (-> (number (list number)) (list number)) (if (null? items) nil (cons (+ n (car items)) (add-n n (cdr items))))) (define (scale-list items factor) ;; TYPE: (-> (number (list number)) (list number)) (if (null? items) nil (cons (* factor (car items)) (scale-list factor (cdr items))))) (map add1 (list 4 5 6)) ==> (5 6 7) (map add1 (list 5 6)) ==> (6 7) (map add1 (list 6)) ==> (7) (map add1 (list)) ==> () (define (map proc items) ;; TYPE: (-> ((-> (S) T) (list S)) (list T)) ------------------------------------------ Q: What's the outline? talk about the "anti-subtraction idea" Q: how do you make 5 from 4? add 1 to it Q: how do you make the list (5 6 7) from the lists (4 5 6) and (6 7)? now generalize. Q: When can't you use map? when the number of outputs is different from the number of inputs **** Compare to Java ***** internal iteration pass the body to the loop, as in Scheme's map show how to do this using interfaces and function objects develop the map method in the class Cons in the library public Cons map(Function body) { return new Cons(body.value(fst), (snd == null) ? null : ((Cons)snd).map(body)); } the Function interface is below --------------------------------------------------------- package lib; public interface Function { Object value(Object x); } --------------------------------------------------------- also show how to call this; I put this in the file lib/ConsTest.java problems: hard to use this to compare collections (dual iteration), slight typing problems in Java (need to overload for mapping in parallel, and different types of function objects) ***** external iteration develop the following interface --------------------------------------------------------- package lib; public interface Iterator { /** are there more elements to be iterated? */ boolean hasMore(); /** move to the next element */ void advance(); /** get the current element */ Object getElement(); } --------------------------------------------------------- then give an implementation of this that can iterate over Cons objects --------------------------------------------------------- package lib; public class ConsIterator implements Iterator { protected Cons Ptr; public ConsIterator(Cons cell) { Ptr = cell; } /** are there more elements to be iterated? */ public boolean hasMore() { return Ptr != null; } /** move to the next element */ public void advance() //@ requires hasMore(); { Ptr = (Cons) Ptr.cdr(); } /** get the current element */ public Object getElement() { return Ptr.car(); } } --------------------------------------------------------- also show how to test this using a for loop Discuss the differences from the standard java.util.Iterator interface and show how to use that (class lib.ConsIterator2)