# Lecture 004

non-negative int lists code step
0 [] base case base case
n > 0 x :: xs inductive / recursive inductive case

## Reason Through Recursive Functions

### Slow

(* length: int list -> int
REQUIRES: true
ENSURES:
*)
fun length ([] : int list): int = 0
| length (x :: xs) = 1 + length xs


This will result adding 1 AFTER recursive call finishes

### Tail Recursive

(* tlength: (int list * int) -> int
REQUIRES: true
ENSURES: tlength (L, acc) ~= (length L ) + acc
*)
fun tlength ([] : int list, acc : int) = 0
| tlength (x::xs, acc) = tlength (xs, 1 + acc)

fun leng (L : int list) = tlength (L, 0)


Since the above function uses tail call (meaning that no work after the recursive call, the final recursive call returns the answer), it conserves space Tail Recursive: every recursive call is a trail call

## Useful Assumption for Induction

### Come To Extensional Equivalence

If $e1 \Rightarrow e2$, then $e1 \simeq e2$ If $e1 \hookrightarrow v2$, then $e1 \simeq e2$ If $e1 \Rightarrow e$ and $e2 \Rightarrow e$, then $e1 \simeq e2$

(Note that $e1 \Rightarrow e$ or $e2 \Rightarrow e$ may not be true even with $e1 \simeq e2$)

Function Simplification: [3/y, 5/2] (fn (x : int) x + y + z) ~= (fn (x:int) => x + 8)

### Using Totality

If f is total: f 1 + f 2 $\simeq$ f 2 + f 1

• when not total, two expression might result different type of exception

Any exception + value is exception, therefore function are not associative in programming

total: for all expression applied to a function, the function reduce to a value valuable: expression reduce to a value without side-effects

## Using Induction

What to induct:

• variable that has base case

• variable that is reducing / not increasing Theorem: tlength (L, acc) ~= length L + acc (for all values L : int list, acc : int) Proof: by structural induction on L Base Case: L = [] WTS tlength ([], acc) ~= length [] + acc (for all values acc : int)

tlength ([], acc) => acc [1st clause of tlength]

length [] + acc
=> 0 + acc [1st clause of length]
=> acc [math]

therefore, tlength([], acc) ~= length [] + acc


Inductive Step: L = x :: xs IH: tlength (xs, acc') ~= length xs + acc' (for any valuable acc') WTS tlength (x::xs, acc) ~= length (x::xs) + acc (for some fixed acc) tlength (x::xs, acc) ~= tlength (xs, 1 + acc) [2nd clause of tlength] ~= length xs + (1 + acc) [IH using acc' = 1 + acc, since we assume acc is valuable] TODO: is this assumption necessary? ~= (1 + length xs) + acc [math, since length is total] ~= length (x::xs) + acc

(* append: int list * int list -> int list
example: append ([1, 2], [3, 4]) => [1, 2, 3, 4]
ruuning time: O(length A)
*)
fun append ([]: int list, B: int list) : int list = B
| append (x:xs, B) = x :: append (xs, B)


This is built in append function that is right associative (infix form = @), meaning everything in the left will be appended one by one to the right

(* rev: int list -> int list
*)
fun rev ([]: int list): int list = []
| rev (x :: xs) = rev xs @ [x]


This reverse function is bad because it has run time O(n^2)

(* trev: (int list * int list) -> int list
REQUIRES: true
ENSURES: trev (L, acc) ~= rev L @ acc
*)
fun trev ([]: int list, acc : int list): int list = acc
| trev (x::xs, acc) = trev (xs, x::acc)


Theorem: trev (L, acc) ~= (rev L) @ acc (for all values L, valuable acc) Proof: by structural induction on L Base Case: L = [] WTS trev ([], acc) ~= rev [] @ acc trev ([], acc) ~= acc [1st clause of trev] ~= [] @ acc [append] ~= rev [] @ acc [1st clause of rev] TODO: see induction step on Piazza

TODO: is there a difference between value and valuable? (coding level difference? proof level difference?)

Table of Content