It would be nice if some people would transfer from section #1 (the 2:30-3:20 one).

Registration system is now online.  Everyone needs to register in order to submit problem sets.  Be sure that when you submit you put both your UID and your partner's UID on the form!

HANDOUT ON WEB

Today's topics:

Part of a theme: FORMAL TOOLS for understanding our programs


We have seen

Today, we dig a little deeper:

1. Processes generated by procedures

2. Correctness of the values they compute

Start developing models for reasoning about whether a procedure computes the desired answer, building on the Substitution Model.

 


 

 

Here are two kinds of multiplication procedures that compute a*n by adding a n times (n is an integer):

(define (times-1 a n)
  (if (= n 0)
      0
      (+ a (times-1 a (- n 1)))))
 
(define (times-2 a n)
  (letrec ((iter (lambda (c result)
                   (if (= c 0)
                       result
                       (iter (- c 1) (+ result a))))))
    (iter n 0)))

 

Note #1: ITER's first argument counts down from b by 1, while it's second argument counts up from 0 by a.

Note #2:

(define (mul x y) (* x y))

is short for

(define mul (lambda (x y)(* x y)))

Note #3: LET is a special form used for binding local variables in general; it temporarily associate name(s) with values, within the body of the form. [Example, with lambda application equivalent.] LETREC is like LET, but is used to define recursive functions. LET and LETREC are  SPECIAL FORMS, which do not follow the normal evaluation rule.

 


 

Let's trace through a computation:

(times-1 6 3)
(+ 6 (times-1 6 2))
(+ 6 (+ 6 (times-1 6 1)))
(+ 6 (+ 6 (+ 6 (times-1 6 0))))
(+ 6 (+ 6 (+ 6 0)))
(+ 6 (+ 6 6))
(+ 6 12)
18

There are a whole slew of DEFERRED OPERATIONS,

On the other hand,

(times-2 6 3)
(iter 3 0)
(iter (- 3 1) (+ 0 6))
(iter 2 6)
(iter 1 12)
(iter 0 18)
18

First arg counts down by 1, second arg counts up by 6.

Note that there are no operations waiting to happen on return.

Also, the size of the expression you are evaluating stays constant.


 

Both times-1 and times-2 are syntactically recursive procedures

BUT:

times-1 generates a RECURSIVE PROCESS:

times-2 generates an ITERATIVE PROCESS

times-1 uses the system to keep track of intermediate computations.

times-2 uses an explicit STATE VARIABLE (result)

-> keeps track of intermediate values.

KEY POINT:

times-2 is TAIL RECURSIVE

 That means, that you don't need to return the value to the previous call of iter! You can just return it back to iter's caller, times-2.

[Note: something can be tail-recursive without calling itself directly! Discussed in section, w/ letrec]

Some languages (such as Scheme) optimize tail-recursive calls so that no extra space is used for each recursive level (when it’s tail recursive). 

 

(Semi-formal) definition:

A function is tail recursive if when you evaluate it under the RSM the expressions you evaluate take a constant amount of space (left-right).


 

Scheme has no special iteration constructs:

while, loop, for, etc.

We just use tail recursion to generate iterative processes

 


 

Next problem:

How do we determine whether times-1 computes the right answer? There are far too many possibilities for us to check them all.

Does it always work? NO. The function clearly loses for n<0.

We'll use MATHEMATICAL INDUCTION and the Substitution Model to reason about values.

KEY IDEA: Show the equivalence of a Scheme program/expression and some mathematical statement about its value (a ``specification'' or ``contract'' that describes what the program computes). Then can think about the program in terms of its contract, rather than its implementation. Allows us to think more abstractly, and also to depend on the given implementation to meet this abstraction.

Here's induction:

First look at case of N = whole numbers = {0, 1, 2, 3, ...}

Suppose that we have some property P[n] which we could ask of a whole number e.g.,

and we want to prove that P holds for all n's.

a. BASIS or BASE CASE:

Prove that P holds for 0.

(the smallest element in the set N).

b. INDUCTION: (to be precise, weak induction – we’ll do strong in section)

Prove for any m in N that, IF P holds for m

THEN P holds for m+1 as well.

 

Notes:

The basis shows that P holds the smallest element (or elements) of the set, which is 0 for N, but other things for other sets.

So,

a. gives us P[0]

b. means P[0] => P[1], so we have P[1]

b. means P[0]/\P[1] => P[2], so we have P[2]

...

 

CONCEPTUALLY:

"Climbing a ladder":

The basis step shows we can get to the bottom step of the ladder.

The induction step shows we can get from one step to the next.

"Knocking over dominos":

The basis step: first domino falls.

The induction step: if N'th (and all previous) falls, so does N+1'st

Induction has a recipe. We expect to see it in your proofs if you want full credit!

INDUCTION RECIPE (the other thing in 212 to memorize!):


See the handout on induction for some examples of mathematical induction problems, and also for some other examples of inductive reasoning about recursive procedures.


Now, let's try an inductive proof that (times-1 a n) = a*n for n >= 0.

[The equivalence of a Scheme program and a mathematical statement.]

Note: induction on n, not a (why?)

Note:

>> Gory detail just to show we can <<

Look at the function. It even looks like an induction:

(define (times-1 a n)
  (if (= n 0)
      ;; basis, when n = 0
      0
      ;; induction step defined in terms of times-1 with smaller arguments
      (+ a (times-1 a (- n 1)))))

VARIABLE: n, whole number

P[b]: (times-1 a n) = a*n

BASIS:

(times-1 a {0}) by the substitution model is

(if (= {0} 0) 0 ...) is

{0}

and that is right, as a*0 = 0.

INDUCTION:

Assume that (times-1 a n) = a*n

Show that (times-1 a n+1) = a*(n+1)

(times-1 a n+1) ==>
(if (= n+1 0)
0
(+ a (times-1 a (- n+1 1))))
==>
;; n+1 can't be 0, since n is a whole number
(+ a (times-1 a (- n+1 1)))
==>
(+ a (times-1 a n))
==>
;; by induction hypothesis
(+ a {a*n})
==>
a+(an)
=
a*(n+1)

So, we've just shown that (times-1 a n) computes a*n for any n>=0 and any number a.

Note that we just obtained infinitely many results!


This degree of effort is excessive for all but the simplest programs.

We will look more later at checking that a procedure's computation meets certain criteria -- "specification"

Automatically generating such "correctness" proofs is an active area

of research.


TODAY'S BIG IDEAS:

The issue is, are there deferred operations (non-constant space in evaluation model)?

New special form: LETREC