# Conference: Week 6

#### Table Of Contents

### 1. Midterm Review

- Instructions on web site.
- Up to
**but not including**exception handling. - Look over HW and solutions. What was the idea behind each question?
- Review lecture notes, class examples, etc.
- Think about class themes.
- No answer should require more than a couple sentences – be concise and precise in your answers!
**Questions?**

### 2. Making Big Lists

Calling the following function `makeList`

with parameter \(n\) creates a list of numbers \(n, \ldots, 2, 1\):

```
fun makeList 0 = []
- -1);
| makeList n = n::makeList(nval makeList = fn : int -> int list
10000;
- makeList val it = [10000,9999,9998,9997,9996,9995,9994,9993,9992,9991,9990,9989,...]
int list :
```

This implementation is not tail recursive. Implement a second version `makeListTailRec`

that is tail recursive. It should have the same behavior as above:

```
10000;
- makeListTailRec val it = [10000,9999,9998,9997,9996,9995,9994,9993,9992,9991,9990,9989,...]
int list :
```

You will need a helper function. Conceal that function inside of `makeListTailRec`

to prevent the client of your code from seeing it.

Time the two versions by repeatedly creating a large list with each. You can use the following code to do that:

```
(*
Time repeated calls to f. The iterations parameter
is the number of calls to make.
Example: Calling
time 100000000 (fn () => abs(5))
measures the time to evaluate "abs(5)" 100,000,000 times.
*)
fun time iterations f =
let fun timeHelper 0 f = ()
-1) f));
| timeHelper n f = (f(); (timeHelper (nval cycles = Timer.startCPUTimer();
val _ = timeHelper iterations f
in
IntInf.toInt(Time.toMilliseconds(#usr(Timer.checkCPUTimer(cycles))))end;
val originalTime = time 100 (fn () => makeList 100000);
val tailrecTime = time 100 (fn () => makeListTailRec 100000);
```

What differences do you see?

### 3. Folding, Redux…

Here are the definitions of our folding operations in ML again:

```
fun foldr f v nil = v
| foldr f v (x::xs) = f (x, foldr f v xs);
fun foldl f v nil = v
| foldl f v (x::xs) = foldl f (f(x, v)) xs;
```

If you have a function that works with either version, which one should you *always* use?

### 4. Tail Recursion (Submit this one with your HW!)

You have git repositories for HW 6 with a starter for this question — you can share that between partners, or just submit your own copy and include the name of your partner at the top.

The dot product of two vectors \([a_1,\ldots,a_n]\) and \([b_1,\ldots,b_n]\) is the sum \(a_1 b_1 + a_2 b_2 + \cdots + a_n b_n\). For example, \[[1,2,3] \cdot [-1,5,3] = 1 \cdot -1 + 2 \cdot 5 + 3 \cdot 3 = 18\] Implement the function

`int list -> int list -> int dotprod:`

to compute the dot product of two vectors represented as lists. You should write this using tail-recursion, so your

`dotprod`

function will probably just be a wrapper function that calls a second function that does all the work. If passed lists of different length, your function should raise a`DotProd`

exception. You will need to declare this type of exception, but you need not catch it.`1,2,3] [~1,5,3]; - dotprod [val it = 18 : int 1,3,9] [0,0,11]; - dotprod [~val it = 99 : int - dotprod [] [];val it = 0 : int 1,2,3] [4,5]; - dotprod [exception DotProd uncaught`

The numbers in the Fibonacci sequence are defined as: \[\begin{array}{rcl} F(0) & = & 0\\ F(1) & = & 1\\ F(n) & = & F(n-1) + F(n-2) \end{array}\] Thus, the sequence is 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, etc.

The following defines a function that returns the n-th Fibonacci number.

`fun slow_fib(0) = 0 1) = 1 | slow_fib(-1) + slow_fib(n-2); | slow_fib(n) = slow_fib(n`

Unfortunately, computing

`slow_fib(n)`

requires \(O(2^n)\) time.Define a tail recursive function

`fast_fib`

that can compute \(F(n)\) in \(O(n)\) time by using tail recursion. (As above,`fast_fib`

will most likely be a wrapper that calls a tail-recursive function.) The tail-recursive function should have only one recursive call in its definition.`0 - fast_fib val it = 0 : int 1 - fast_fib val it = 1 : int 5 - fast_fib val it = 5 : int 10 - fast_fib val it = 55 : int`

Hint: When converting

`sumSquares`

to tail-recursive form, we introduced one auxiliary parameter to accumulate the result of the single recursive call in that function. How many auxiliary parameters do you think we will need for`fibtail`

?Use the

`time`

function to see how much faster the tail recursive function can be, even for relatively small \(n\).

### 5. Memoization (optional)

Our tail recursive `fast_fib`

takes linear time, but it requires a quite different approach to the problem. An alternative is to use *memoization*, a general technique that works for many algorithms. Memoization is similar to dynamic programming, which you will see in algorithms.

The idea is to have your algorithm keep a table of previously-computed results that it can consult. For example if we must compute \(F(15)\), we first consult the table to see if we already know the answer before doing any additional work.

You will complete a memoized `memo_fib`

using this technique. For the table, we’ll use our basic table definition from a couple weeks ago. Tables are have type `''a * 'b list`

, where `''a`

is the key type and `'b`

is the value type. Here’s our lookup function that returns a `'b option`

of `NONE`

or `SOME(v)`

:

```
fun get (k, nil) = NONE
| get (k, (key,value)::rest) =if k = key then SOME(value)
else get(k, rest);
```

(Of course, our tables have linear-time lookup. They get the job done for illustration purposes, but for a better implementation, you would choose a data structure with constant-time lookups, such as a hash table.) Here’s the general structure of our memoized function:

```
fun memo_fib n =
let val table = ref nil; (* tabled -- shared among all calls to the helper *)
fun memo_fib_helper n =
case get(n, !table) of (* check if already in table *)
(* Yep! Just return the value we found *)
SOME(v) => v (* Nope! *)
| NONE => (* Compute r = F(n), insert into table, return r. *)
... in
memo_fib_helper nend;
5;
memo_fib 50; memo_fib
```

We must ensure that *all* calls to `memo_fib_helper`

use the same memoization table. Thus, we create a mutable reference `table`

that is visible only within the scope of `memo_fib`

. Complete the definition by filling in the `NONE`

case.