CSC153 2004S, Class 9: Preconditions and Postconditions
Admin
* HW1 not graded yet
* Interesting Convo tomorrow
* Read "Local Procedure Bindings with letrec"
* Lots of discussion today, just a little lab
* Test coming: Distributed next Monday, due a week from next Wednesday.
Overview
* Past topics, revisited
* Efficient computation of exponentiation? [Thursday]
* On the ordering of let vs. lambda
* Why document?
* The Six P's
* Writing robust code
* Reporting on errors
* Husk and Kernel programming
* Example: sum-of-squares
* Lab
Ordering let and lambda
(define fourthblue
(lambda (x)
(let ((square (lambda (y) (* y y))))
(square (square x)))))
(define fourthred
(let ((square (lambda (y) (* y y))))
(lambda (x)
(square (square x)))))
(define square-all-blue
(lambda (lst)
(let ((square (lambda (y) (* y y))))
(if (null? lst) null
(cons (square (car lst)) (square-all-blue (cdr lst)))))))
(define square-all-red
(let ((square (lambda (y) (* y y))))
(lambda (lst)
(if (null? lst) null
(cons (square (car lst)) (square-all-red (cdr lst)))))))
See square-all.scm for an example
Moral: Whenever possible, put your lets outside your lambdas
/Documentation in Scheme/
* How: A comment is any text that begins with a semicolon and ends with the end of line
* What: Something to be read by the human reader and not the computer
* Example:
(let ((stddev (sqrt variance))) ; Prof. Kupier told me so
* Why?
* To help "other people" read your code.
* Programming is collaborative: Why reinvent when you can reuse?
* Programming is incremental: Others may have to debug/correct your code.
* Most people forget what they've done - You soon become the "other"
* Easier to use if you know what it's supposed to do
* How? revised
* Write the comments, first!
* What, revised
* Each procedure should be documented as to its primary purpose: People can use the procedure if they know *what* it does, even if they don't understand how.
* The particular details of the implementation should be documented so that the maintainer/debugger/etc.
* General design of the program; Assumptions, etc..
* Authorship, table-of-contents, etc.
/The Six P's/
* Procedure: Name it
* Parameters: Name and Type them
* Types are "how the computer looks at the information"
* Examples: Integer, Real, string, list of strings, ...
* Purpose: Short description of what the procedure is expected to.
* Produces: Name and type of result
* Preconditions: Semi-formal specification of non-type requirements.
* Postconditions: Semi-formal specification of results.
Example:
/*
* Procedure:
* square
* Parameters:
* x, an integer (int)
* Purpose:
* Compute the square of x.
* Produces:
* square-of-x, an int
* Preconditions:
* x must be in the range [-sqrt(largest-int) ... sqrt(largest-int)]
* Postconditions:
* square-of-x = x*x
*/
int square(int x)
{
return x*x;
} // square(int)
Philosophy:
* Computing is an adversarial enterprise
* Programmer vs. other programmer
* The "client" of a procedure excepts it to work in all cases for which the preconditions are met
* The "author" of a procedure wants to do as little work as possible
Educational Philosophy:
* Thinking carefully about failure is useful.
Computing Philsophy, Revisited:
* Belief one: Stating them is enough.
* Easier for you as a programmer.
* Much more efficient: You don't have to check every time.
* Belief two: Check for them and report an appropriate error.
* More helpful for someone who actually has to deal with the program.
* Belief three: Provide two versions of every procedure, one that checks preconditions and one that doesn't.
In Scheme, you can use the error procedure to report errors.
* Prints a nice bug.
* Prints an error message that you supply.
* Stops computation immediately
If you do your checking particularly badly, it can be really inefficient.
(define square-all
(lambda (lst)
(cond
((null? lst) null)
((all-numbers? lst) (cons (square (car lst)) (square-all (cdr lst))))
(else (error 'square-all "expects a list of all numbers")))))
The solution: Iowa's contribution to the programming world
* "Husk and Kernel programming"
* The kernel is the valuable part
* The husk protects the kernel
(define square-all
(lambda (lst)
(if (all-numbers? lst)
(square-all-kernel lst)
(else (error 'square-all "expects a list of all numbers")))))
(define square-all-kernel
(if (null? lst) null)
(cons (square (car lst)) (square-all-kernel (cdr lst))))