On this page:
Updates
Introduction
Advice
Part 0:   Binary trees
Part 1:   Tries
Part 2:   Lambda Calculus
Part 3:   Unit Testing
What to Turn In
Academic Integrity
6.4

Project 1: OCaml Warmup

Due: Tues, Feb 16, 2015 11:59:59pm

Updates
Introduction

This project will help refresh your memory on programming in OCaml by asking you to write two small modules and then develop test cases for them. You may find it helpful to review the OCaml slides from CMSC 330.

Advice
Part 0: Binary trees

This is not part of the project; it is only here as a warm-up to the rest. Try to do these finger exercises first. If you have trouble, don’t try to proceed to the rest of the project, but rather try to master these simpler concepts first. You do not have submit this code and it will not be graded if you do.

Here’s a type for binary trees:

type 'a bt =

  | Leaf

  | Node of 'a * 'a bt * 'a bt

Implement the following functions:

(** does the tree contain an element equal to the given one? *)

val contains : 'a bt -> 'a -> bool

 

(** produce elements in the left-to-right order they appear in the tree *)

val to_list : 'a bt -> 'a list

 

(** zip together two binary trees with same shape; fail if not same shape *)

val zip : 'a bt -> 'b bt -> ('a * 'b) bt

 

(** produce tree of same shape, every element is obtained by applying f *)

val map : 'a bt -> ('a -> 'b) -> 'b bt

 

(** produce the mirror image of a tree; elements are in reverse order *)

val rev : 'a bt -> 'a bt

 

(** list List.fold but for binary trees *)

val fold : 'a bt -> 'b -> ('a -> 'b -> 'b -> 'b) -> 'b

A path is a list of directions, which are either left or right, and can describe a path to an element in a binary tree:

type dir = Left | Right

Write a function the gets the element found by following a given path. This function should fail if the path goes off the end of the tree:

(** get the element found by following given path *)

val get : 'a bt -> dir list -> 'a

A binary search tree is binary tree with an ordering on elements such that all elements in the left subtree of a node are less than or equal the value of the node and all elements in the right subtree.

Here’s one possible type for binary search trees:

type 'a bst = ('a -> 'a -> bool) * 'a bt

Think of the comparison function like (<=).

Implement the following functions:

(** insert the given element into bst *)

val bst_insert : 'a bst -> 'a -> 'a bst

 

(** does the bst contain an element equal to the given one? *)

val bst_contains : 'a bst -> 'a -> bool

 

(** delete the first occurrence of given element; fail if it doesn't exist *)

val bst_delete : 'a bst -> 'a -> 'a bst

Using your implementation of binary search trees, implement a sorting algorithm that consumes a list of elements and produce the same list of elements but in sorted order.

val sort : ('a -> 'a -> bool) -> 'a list -> 'a list

Part 1: Tries

Your first task is to implement tries, which are data structures designed for fast access to data indexed by sequences such as strings. More precisely, we’ll use the following type for tries:

type ('k, 'v) trie = Trie of 'v option * (('k * ('k, 'v) trie) list)

Here a (k, v) trie maps lists of keys of type k to values of type v. For example, if we wanted to map strings to the number of times they appear in a text, we might use a (char list, int) trie. A node in a trie is a pair containing an optional value and a list of (key, trie) pairs. For example, here are some tries:

(* empty trie *)

Trie (None, [])

 

(* maps ['a'] to 1 *)

Trie (None, ['a', Trie (Some 1, [])])

 

(* maps ['a'] to 1 and ['b'] to 2 *)

Trie (None, ['a', Trie (Some 1, []);

             'b', Trie (Some 2, [])])

 

(* maps ['a'; 'b'] to 1 *)

Trie (None, ['a', Trie (None, ['b', Trie (Some 1, [])])])

 

(* maps ['a'; 'b'] to 1 and ['a'; 'c'] to 2 *)

Trie (None, ['a', Trie (None, ['b', Trie (Some 1, []);

                               'c', Trie (Some 2, [])])])

 

(* maps [] to 1, ['a'] to 2, ['a'; 'b'] to 3 and ['a'; 'c'] to 4 *)

Trie (Some 1, ['a', Trie (Some 2, ['b', Trie (Some 3, []);

                                   'c', Trie (Some 4, [])])])

You must use the type signature given above to implement tries. You should implement the following functions:

type ('k, 'v) trie

 

val empty : ('k, 'v) trie

val is_empty : ('k, 'v) trie -> bool

val insert : ('k, 'v) trie -> 'k list -> 'v -> ('k, 'v) trie

val find : ('k, 'v) trie -> 'k list -> 'v

val delete : ('k, 'v) trie -> 'k list -> ('k, 'v) trie

val height : ('k, 'v) trie -> int

val width : ('k, 'v) trie -> int

val map : ('k, 'v) trie -> ('v -> 'u) -> ('k, 'u) trie

val iteri : ('k, 'v) trie -> ('k list -> 'v -> unit) -> unit

val compress : ('k, 'v) trie -> ('k, 'v) trie

You’ll find the types above in the interface file "trie.mli", and you should put your implementation in "trie.ml". You can find more detailed descriptions of the above functions in the ".ml" file, though probably you can guess how these should behave.

Part 2: Lambda Calculus

Your next task is to implement a few functions related to Lambda calculus, which you learned about in CMSC 330. Below is an interface file "lambda.mli". You must implement the last six of the listed functions in "lambda.ml". (We’ve already implemented unparse for you.)

type expr =

| Var of string

| Lam of string * expr

| App of expr * expr

 

val unparse : expr -> string

 

val free_vars : expr -> string list

val is_alpha : expr -> expr -> bool

val subst : string -> expr -> expr -> expr

val beta : expr -> expr option

val normal_form : expr -> expr

val expr_of_int : int -> expr

val add : expr -> expr -> expr

These functions should do the following:

Part 3: Unit Testing

Your last task is to write unit tests for parts 1 and 2 above, using OUnit. Put your test cases in the file "test.ml", and be sure to add your test cases to the suites suite_trie and suite_lambda, as appropriate. We will grade this part of the project by running your test cases against various correct and incorrect implementations. A test case will only be counted as correct if it passes a correct implementation and fails at least one incorrect implementation.

What to Turn In

Put all your code in the code skeleton we have supplied, and upload your solution to the submit server. You can either upload your solution via the web interface, or you can run java -jar submit.jar in the project directory.

Important note: On GRACE you should use the version of OCaml installed in the public directory for this course. It is version 4.02.3 and has the ocamlfind and ounit libraries pre-installed. To access this version of ocaml, run the following command after logging in to grace.umd.edu:

$ source /afs/glue.umd.edu/class/spring2016/cmsc/430/0101/public/opam-init/init.csh

You can confirm you have the new version of OCaml as follows:

$ ocaml -version

The OCaml toplevel, version 4.02.3

If you want to make so that you always use the new version of OCaml, you can create (or edit, if it exists) the file .startup.tty in your home directory and add the source command from above. Running the following will add this line to that file. After doing this, the newer version of OCaml will be available when you log in without having to the source thing every time:

$ touch .startup.tty

$ echo 'source /afs/glue.umd.edu/class/spring2016/cmsc/430/0101/public/opam-init/init.csh' >> .startup.tty

To test this, log out, log back in. If you run ocaml, you should see 4.02.3.

You should now be able to download, unpack, and compile the code skeleton for Project 1 on GRACE. Here’s a sample, showing how to do it:

$ curl -s http://www.cs.umd.edu/class/spring2016/cmsc430/p1.tar.gz | tar -xz

$ cd p1/

$ make

ocamlbuild main.native -pkgs oUnit

Finished, 7 targets (0 cached) in 00:00:00.

$ ./main.native

<....testing output....>

Ran: 1 tests in: 0.00 seconds.

OK

Please post any questions you have about this on Piazza. You are welcome to install OCaml on your own machine, though we can’t provide much support for that. We do recommend using opam to manage the installation process if you choose to do that. You can use opam to install both OCaml and OUnit.

Academic Integrity

The Campus Senate has adopted a policy asking students to include the following statement on each assignment in every course: “I pledge on my honor that I have not given or received any unauthorized assistance on this assignment.” Consequently your program is requested to contain this pledge in a comment near the top.

Please carefully read the Academic Integrity section of the course syllabus. Any evidence of impermissible cooperation on projects, use of disallowed materials or resources, or unauthorized use of computer accounts, will be submitted to the Student Honor Council, which could result in an XF for the course, or suspension or expulsion from the University. Be sure you understand what you are and what you are not permitted to do in regards to academic integrity when it comes to project assignments. These policies apply to all students, and the Student Honor Council does not consider lack of knowledge of the policies to be a defense for violating them. Full information is found in the course syllabus—please review it at this time.

 

Web Accessibility