CSC151 2007S, Class 24: Documenting Programs and Procedures Admin: * Reading for Thursday: Verifying Preconditions. * Homework for Friday: Assignment 10: Documentation. * Food! Cookies and Twizzlers * EC: Thursday, 4:15 snacks, 4:30 talk: TEmily on "Efficient Pixel Manipulation in the GIMP" Overview: * Recursion * Basic concepts * Patterns * Example: Three versions of rgb.brightest * Watching the code work * Documentation * The need for documentation. * The Six P's - a strategy for documenting procedures. * Practice. /Recursion: The Basics/ * Purpose: General technique for repeating actions * Common instance so far: Compute some value that may require looking at every element of a list * What might we compute? * A new list, in which we apply a procedure to each element of the original list: * map will do this, too * A new list, which contains only selected elements of the original list * map builds an equal size list, so IT WON'T WORK HERE * Example: Filter out dark colors from a list, because darkness disturbs * Example: The anti-grinnellian filter: Get rid of odds * Example: Filter out spots that can't be drawn in a particular image, because row or column is too small or too large * A number, based on some attributes of the elements of the list * map builds lists, NOT NUMBERS * Example: Add up all the red components * Perhaps because this will be useful in creating new images * Example: Count values in a list that meet some criteria * Example: Find out where in a list a number appears * A Boolean, " " " * map builds lists, NOT BOOLEANS * Example: Can we draw any of these spots in a region * Can use recursion to compute other kinds of values (preview of next week or the week after break), but WE'LL STICK WITH LISTS We've established the purpose, what is the technique? * Use a call to *the same procedure* on *a simplified input* * Use that result to compute an overall result * Write a conditional to determine whether we should recurse, or simply use an easy-to-cmopute result Theory is fine, what does the CODE look like? MOST GENERAL FORM (define __proc__ (lambda (__params__) (if (___simple___ ___params___) (___easycomp___ ___params___) (__combine___ ___params___ (__proc___ (___simplify__ __params__)))))) What might the combination be? * Problem: Count the number of odd students in a list of students * Suppose we know how many odd students appear in the cdr * If the car is odd, we add 1 to that number * If the car is not odd, we add 0 to that number (define students.tally-odd (lambda (students) (if ____ ____ (+ (if (student.odd? (car students)) 1 0) (students.tally-odd (cdr students)))))) (define __proc__ (lambda (lst) (if (null? lst) _some_base_value (__combine___ (car lst) (__proc___ (cdr lst)))))) Example: SUM (define sum (lambda (lst) (if (null? lst) 0 (+ (car lst) (sum (cdr lst)))))) BUT ... SOMETIMES WE WANT TO MAKE CHOICES BASED ON THE CAR (define __proc__ (lambda (lst) (cond ((null? lst) _some_base_value) ((__special__ (car lst)) (__action__ (__proc__ (cdr lst)))) (else (__proc___ (cdr lst)))))) Alternate definition of students.tally-odd (define students.tally-odd (lambda (lst) (cond ((null? lst) 0) ((student.odd? (car lst)) (+ 1 (students.tally-odd (cdr lst)))) (else (students.tally-odd (cdr lst)))))) So, where are those 1's going? (students.tally-odd (list john carter amanda laurab laurag)) => (+ 1 (students.tally-odd (cdr (list john carter amanda laurab laurag)))) => (+ 1 (students.tally-odd (list carter amanda laurab laurag)))) ; Assume carter is NOT odd => (+ 1 (students.tally-odd (list amanda laurab laurag)))) => (+ 1 (+ 1 (students.tally-odd (cdr (list amanda laurab laurag))))) => (+ 1 (+ 1 (students.tally-odd (list laurab laurag))))) => (+ 1 (+ 1 (+ 1 (students.tally-odd (cdr (list laurab laurag)))))) => (+ 1 (+ 1 (+ 1 (students.tally-odd (list laurag))))) => (+ 1 (+ 1 (+ 1 (+ 1 (students.tally-odd (cdr (list laurag))))))) => (+ 1 (+ 1 (+ 1 (+ 1 (students.tally-odd null))))) => (+ 1 (+ 1 (+ 1 (+ 1 0)))) => (+ 1 (+ 1 (+ 1 1))) => (+ 1 (+ 1 2)) => (+ 1 3) => 4 Let's use this to compute the brightest element in a list * When computing an element of the list, THAT LIST MUST HAVE AT LEAST ONE ELEMENT (define __proc__ (lambda (lst) (cond ((null? (cdr lst)) (car lst)) ((__special__ (car lst)) (__action__ (__proc__ (cdr lst)))) (else (__proc___ (cdr lst)))))) (define rgb.brightest (lambda (lst) (cond ((null? (cdr lst)) (car lst)) ; If the car of the list is really bright, say brighter than ; the remaining elements ((rgb.brighter? (car lst) (rgb.brightest (cdr lst))) (car lst)) ; Otherwise, use the brightest remaining elment (else (rgb.brightest (cdr lst)))))) (define student.oddest (lambda (lst) (cond ((null? (cdr lst)) (car lst)) ; If the car of the list is really odd, say odderthan ; the remaining elements ((student.odder? (car lst) (student.oddest (cdr lst))) (car lst)) ; Otherwise, use the oddest remaining elment (else (student.oddest (cdr lst)))))) (student.oddest (list yok mario hanna hannah steven)) => Test if the car is odder than the oddest remaining element Detour: (student.oddest (list mario hanna hannah steven) Test if the car is odder than the oddest remaining element Detour: (student.oddest (list hanna hannah steven) Test if the car is odder than the oddest remaining element Detour: (student.oddest (list hannah steven) Test if the car is odder than the oddest remaining element Detour: (student.oddest (list steven)) Done with the recursive calls: steven is oddest * Is hannah odder than steven. No. * steven is oddest remaining student * Is hanna odder than steven. Yes * hanna is oddest of (hanna hannah steven) * Is mario odder than hanna. Definitely not. * hanna is oddest of (mario hanna hannah steven) * yok is odder than hanna, by dictates of the evil profesor * yok is oddest of (yok mario hanna hannah steven) WE RETURN TO DOCUMENTATION ON THURSDAY, ALONG WITH TAIL RECURSION