CSC 151, Class 21: Preconditions, Postconditions, and More Overview: * Why document? * Where to document? * The six P's. * Robustness: Exiting upon error. * Example: sum-of-squares. * Husk-and-kernel programming. * Lab Notes: * Report from Sam's weekend trip. * Are there questions on Exam 1? + Note about Sam's grading style. * Are there questions on writeup 2? * Are there questions on Friday's class? * Read: Local Bindings with let * Warning; HW 3 Friday ---------------------------------------- Observation: Programs are unlike many other intellectual results: People use procedures and hope that (1) they understand what the procedures are doing; (2) the procedures are correct. To clarify things for others, we need to write *documentation* Different kinds of documentation: * For individual procedures, explaining what they do. + Six P's + Goal: Formalize inputs and outputs of procedures. * For individual procedures, explaining *how* they meet their goals. + Use it as the basis of similar procedures + Fix nonworking procedures * For groups of procedures (whole programs) explaining their structure. Preconditions: Formalize the state of "the world" that must hold in order for the procedure to work. Postconditions: Formalize the state of "the world" after the procedure finishes. What happens if your preconditions are not met? * Report an error. * Adapt. * "It's not my problem" Let's look at a sample problem: * Given a list of integers, * Sum their squares Formalize Precondition: * lst has the form (val1 val2 ... valn) * lst is of length at least 1 * all the values in lst are integers Postcondition: * sum = val1*val1 + val2*val2 + ... + valn*valn (define sum-of-squares (lambda (lst) (if (null? (cdr lst)) (* (car lst) (car lst)) (+ (* (car lst) (car lst)) (sum-of-squares (cdr lst)))))) (sum-of-squares (list 1 2 3)) => (+ (* 1 1) (sum-of-squares (list 2 3))) => (+ 1 (sum-of-squares (list 2 3))) => (+ 1 (+ (* 2 2) (sum-of-squares (list 3)))) => (+ 1 (+ 4 (sum-of-squares (list 3)))) => (+ 1 (+ 4 9)) => (+ 1 13) => 14 How would we check that lst is a list of integers? (define list-of-integers? (lambda (something) ...)) Suppose we'd defined list-of-integers? (or someone had defined it). How might we change the definition? (define sum-of-squares (lambda (lst) (if (and (list-of-integers? lst) (not (null? lst))) (if (null? (cdr lst)) (* (car lst) (car lst)) (+ (* (car lst) (car lst)) (sum-of-squares (cdr lst)))) (error 'sum-of-squares "That's not a list of integers!")))) Whaddaya think? * Improved error checking (fixed) * What about letting cdr report the error? (no) (sum-of-squares (list 1 2 3 4 5 6)) => (+ (* 1 1) (sum-of-squares (list 2 3 4 5 6))) => (+ 1 (sum-of-squares (list 2 3 4 5 6))) n + n-1 + n-2 + ... + 1 = n(n+1)/2 Iowa comes to the rescue! husk-and-kernel Idea: The husk checks the preconditions (once!) and then calls the kernel. The kernel does the real work. Naming: The husk protects the kernel, so the kernel doesn't have to protect itself. (define sum-of-squares (lambda (lst) (if (and (list-of-integers? lst) (not (null? lst))) (sum-of-squares-kernel lst) (error 'sum-of-squares "That's not a list of integers!")))) (define sum-of-squares-kernel (lambda (lst) (if (null? (cdr lst)) (* (car lst) (car lst)) (+ (* (car lst) (car lst)) (sum-of-squares-kernel (cdr lst))))