# CS334: HW 3

#### Table Of Contents

## Instructions

This homework has three types of problems:

**Self Check:**You are strongly encouraged to think about and work through these questions, but you will not submit answers to them.**Problems:**You will turn in answers to these questions.**Pair Programming:**This part involves writing ML code.*You are*You are welcome to choose your own partner, but I can also assist in matching pairs — simply send me a Slack message and I will pair you with someone else also looking for a partner. Please do not let finding a partner go until the last minute.~~required~~**strongly encouraged**to work with a partner on it.

## Reading

**(Required)**Read Mitchell, skim 4.4–4.5, 5, skim 6.1.**(As necessary)**ML documentation and tutorials. These two may be particularly useful:**(Optional)**J. Backus, Can programming be liberated from the von Neuman style?, Comm. ACM 21, 8 (1978) 613-641. You can find this on the cs334 web site.

## Self Check

### ML Types

*Mitchell, Problem 6.1*

## Problems

### 1. Lazy Evaluation and Parallelism (20 pts)

*Mitchell, Problem 4.11*

The function g should be defined as follows (there is a typo in the book):

```
fun g(x, y) = if x = 0
then 1
else if x + y = 0
then 2
else 3;
```

### 2. Algol 60 Procedure Types (5 pts)

*Mitchell, Problem 5.1*

### 3. Translation into Lambda Calculus (10 pts)

*Mitchell, Problem 4.6*

## ML Programming (50 pts)

For this problem, use the ML interpreter on the Unix machines in the computer lab, or on your own computer. See instructions here.

Your GitLab account will have a project for your to use for this question. You can follow the same instructions as on HW 1 for cloning it and adding a partner. You should answer the following in the `*.sml`

files in your repository.

You can run ML on the file “example.sml” as follows:

`sml < example.sml`

at the command line. As with Lisp, the ML compiler will process the program in the file and print the result. For example, if “example.sml” contains

```
(* double an integer *)
fun double (x) = x * x;
(* return the length of a list *)
fun listLength (nil) = 0
1 + listLength ls
| listLength (l::ls) =
;
10);
double (1::[2,3,4]); listLength (
```

the command `sml < example.sml`

will produce the following:

```
val double = fn : int -> int
val listLength = fn : 'a list -> int
val it = 100 : int
val it = 4 : int
```

You can also run `sml`

and enter in declarations and expressions to evaluate at the prompt.

Start early on this part so you can get in touch with me or the TAs if you have problems understanding the language. There are many valuable resources available to help you learn ML:

The examples in the

*Mitchell*book and in your notes.Several very good tutorials listed on the resources page. Of particular note:

A few additional details:

Emacs on the Unix machines will provide auto-formatting and syntax highlighting while editing ML files.

**Be sure your file names end with “.sml” so Emacs can recognize them as containing ML code.**Comments in ML are delineated by

`(*`

and`*)`

.Put the following line at the top of your ML files to ensure that large data types and lists are fully printed:

`100; Control.Print.printDepth := 100; Control.Print.printLength :=`

Unless otherwise specified, you should use pattern matching where possible.

There are several thought questions in the descriptions below. Please answer these questions with your partner in comments in the code.

### 1. Basic Functions

Define a function `sumSquares`

that, given a nonnegative integer n, returns the sum of the squares of the numbers from 1 to n:

```
4)
- sumSquares(val it = 30 : int
5)
- sumSquares(val it = 55 : int
```

Define a function `listDup`

that takes an element, e, of any type, and a non-negative number, n, and returns a list with n copies of e:

```
"moo", 4);
- listDup(val it = ["moo","moo","moo","moo"] : string list
1, 2);
- listDup(val it = [1,1] : int list
"cow", 2), 2);
- listDup(listDup(val it = [["cow","cow"],["cow","cow"]] : string list list
```

##### Question

Your function will have a type like `’a * int -> ’a list`

. What does this type mean? Why is it the appropriate type for your function. Answer this question as a comment in the code.

### 2. Zipping and Unzipping

Write the function `zip`

to compute the product of two lists of arbitrary length. You should use pattern matching to define this function:

```
1,3,5,7] ["a","b","c","de"];
- zip [val it = [(1,"a"),(3,"b"),(5,"c"),(7,"de")]: (int * string) list
```

Note: This is the curried version with type `’a list -> ’b list -> (’a * ’b) list`

. Be sure to define it to match this type.

Also, if the lists don’t have the same length, you may decide how you would like the function to behave. If you don’t specify any behavior at all you will get a “match not exhaustive” warning from the compiler to indicate that you have not taken care of all possible patterns— this is fine.

Write the inverse function, `unzip`

, which behaves as follows:

```
1,"a"),(3,"b"),(5,"c"),(7,"de")];
- unzip [(val it = ([1,3,5,7], ["a","b","c","de"]): int list * string list
```

Write `zip3`

, to zip three lists.

```
1,3,5,7] ["a","b","c","de"] [1,2,3,4];
- zip3 [val it = [(1,"a",1),(3,"b",2),(5,"c",3),(7,"de",4)]: (int * string * int) list
```

##### Question

Why can’t you write a function `zip_any`

that takes a list of any number of lists and zips them into tuples? From the first part of this question it should be pretty clear that for any fixed n, one can write a function `zipn`

. The difficulty here is to write a single function that works for all n. In other words, can we write a single function `zip_any`

such that `zip_any [list1,list2,...,listk]`

returns a list of k-tuples no matter what k is? Answer this question as a comment in the code.

### 3. Find

Write a function find with type `”a * ”a list -> int`

that takes a pair of an element and a list and returns the location of the first occurrence of the element in the list. For example:

```
3, [1, 2, 3, 4, 5]);
- find(val it = 2 : int
"cow", ["cow", "dog"]);
- find(val it = 0 : int
"rabbit", ["cow", "dog"]);
- find(val it = ~1 : int
```

First write a definition for find where the element is guaranteed to be in the list. Then, modify your definition so that it returns `~1`

if the element is not in the list.

### 4. Trees

Here is the datatype definition for a binary tree storing integers at the leaves:

`datatype IntTree = LEAF of int | NODE of (IntTree * IntTree);`

Write a function `sum:IntTree -> int`

that adds up the values in the leaves of a tree:

```
3);
- sum(LEAF val it = 3 : int
2, LEAF 3));
- sum(NODE(LEAF val it = 5 : int
2, NODE(LEAF 1, LEAF 1)));
- sum(NODE(LEAF val it = 4 : int
```

Write a function `height: IntTree -> int`

that returns the height of a tree:

```
3);
- height(LEAF val it = 1 : int
2, LEAF 3));
- height(NODE(LEAF val it = 2 : int
2, NODE(LEAF 1, LEAF 1)));
- height(NODE(LEAF val it = 3 : int
```

Write a function `balanced: IntTree -> bool`

that returns true if a tree is balanced (ie, both subtrees are balanced and differ in height by at most one). You may use your `height`

function in the definition of `balanced`

.

```
3);
- balanced(LEAF val it = true : bool
2, LEAF 3));
- balanced(NODE(LEAF val it = true : bool
2, NODE(LEAF 3, NODE(LEAF 1, LEAF 1))));
- balanced(NODE(LEAF val it = false : bool
```

##### Question

What is non-optimal about using the `height`

function in the definition of `balanced`

? Can you suggest a more efficient implementation? You need not write code, but describe in a sentence or two how you would do this. Answer this question as a comment in the code.

### 5. Stack-based Evaluator

Certain programming languages (and HP calculators) evaluate expressions using a stack. As I am sure many of you learned in cs136, PostScript is a programming language of this ilk for describing images when sending them to a printer. We are going to implement a simple evaluator for such a language. Computation is expressed as a sequence of operations, which are drawn from the following data type:

```
datatype OpCode =
of real
PUSH
| ADD
| MULT
| SUB
| DIV
| SWAP ;
```

The operations have the following effect on the operand stack. (The top of the stack is shown on the left.)

OpCode | Initial Stack | Resulting Stack |
---|---|---|

`PUSH(r)` |
... | r ... |

`ADD` |
a b ... | (b + a) ... |

`MULT` |
a b ... | (b * a) ... |

`SUB` |
a b ... | (b - a) ... |

`DIV` |
a b ... | (b / a) ... |

`SWAP` |
a b ... | b a ... |

The stack may be represented using a list for this example, although we could also define a stack data type for it.

`type Stack = real list;`

Write a recursive evaluation function with the signature

`list * Stack -> real eval : OpCode `

It takes a list of operations and a stack. The function should perform each operation in order and return what is left in the top of the stack when no operations are left. For example,

`2.0),PUSH(1.0),SUB],[]) eval([PUSH(`

returns 1.0. The `eval`

function will have the following basic form:

```
fun eval (nil,a::st) = (* ... *)
(* ... *)
| eval (PUSH(n)::ops,st) = (* ... *)
| 0.0
| eval (_,_) = ;
```

You need to fill in the blanks and add cases for the other opcodes.

The last rule handles illegal cases by matching any operation list and stack not handled by the cases you write. These illegal cases include ending with an empty stack, performing addition when fewer than two elements are on the stack, and so on. You may ignore divide-by-zero errors for now (or look at exception handling in the online resources – we will cover that topic in a few weeks).

If you wrote a PostScript interpreter in cs136, compare that experience to this one. In particular, what advantages does ML offer for writing this type of program? (No need to write an answer to this question, but come ready to talk about it at the next lecture).

## What To Turn In

#### Problems

Your submitted homework should:

- be clearly written or typed,
- include your name and HW number at the top,
- list any students with whom you discussed the problems,
- be a single PDF file, with one problem per page, and
- be submitted to Gradescope by the due date.

#### Programming

Your submitted programs should:

- be readonably documented and tested,
- list any students with whom you discussed the programming,
- be committed and pushed to your GitLab repository by the due date, and
- be submitted to Gradescope by the due date.

To submit your code in Gradescope, navigate to the submission page for this assignment’s programming component, and select the option to submit files. Then select and upload your source files. If you worked with a partner, only one of you should submit your code, and please indicate who your partner is when you upload your files.

*Note:* The shared repository you are using is either your own or your partners. The other one will be unused. There is no need to do anything to that repository. Our submission scripts will ignore unused repositories and look only at the onces with completed solutions.