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))))