Due date: Tuesday, September 10th, 11:59PM
In this course, we use OCaml for most programming assignments. This tutorial only covers the tiny sliver of OCaml you truly need to do the assignments. The course also uses tools and testing extensions that are not part of the standard OCaml distribution; this tutorial introduces them too.
The tutorial is divided into several sections. Each section introduces new OCaml features, provides some examples, and concludes with exercises that you should do. The solutions to all exercises are provided, but you should try to do the exercises before you click "show solution".
OCaml is a sophisticated programming language with several advanced features. We encourage you to explore OCaml on your own. There are several other tutorials and guides on the Ocaml Website. Real World OCaml is an excellent book that covers the language and programming pragmatics in depth.
Prerequisite: You must install the course software, which includes OCaml to do this tutorial. Do ask for help if you have trouble installing the software.
A simple OCaml program is a sequence of declarations, followed by
  a main expression. You must use a double-semicolon (;;) 
  to separate the declarations from the main expression. E.g.:
let x : int = 23
let y : int = 60
let sum : int = x + y
let message : string = "The sum is " ^ string_of_int sum ^ ".\n"   
;;
print_string message In this example, all the declarations are let declarations. (We introduce a few other kinds of declarations momentarily.) A let declaration states the name of the bound identifier, its type, and the bound expression. Unlike more complex languages, OCaml does not automatically convert between values of different types. For example, the code above explicitly applies string_of_int . Without this conversion, the OCaml compiler woudl fail with a type error:
This expression has type int but an expression was expected of type string.
Similarly, OCaml has no function or operator overloading. In many languages,
x + y may mean "add two numbers" or "concatenate two strings". 
In OCaml these two operations are distinct: x ^ y means string 
concatenation and x + y means integer addition. Incidentally, 
x +. y means floating point addition.
In OCaml, we can declare functions using a variation of let declarations:
let increment (a : int) : int =
  a + 1
let add_three (x : int) (y : int) (z : int) : int =
  x + y + z
let make_message (n : int) : string =
  "The sum is " ^ string_of_int n ^ ".\n"   
;;
print_string (make_message (add_three 1 2 3))
In these declarations, each function argument has a name and type enclosed in parentheses. The final type in the declaration is the type of the function result.
Pay close attention to the syntax of function application in the main expression. A function application uses spaces to separate the function from each argument. The parentheses simply ensure that arguments are properly grouped. For example, suppose we missed the inner parentheses and wrote:
print_string (make_message add_three 1 2 3)This expression applies make_message to four arguments, but
  it expects only one, so we have a type error. Similarly, suppose
  we missed the outer parentheses:
print_string make_message (add_three 1 2 3)This expression applies print_string to two arguments, but
  it expects only one, so we have another type error. When it doubt, use
  parentheses for clarity.
In OCaml, let does not introduce a recursive binding.
  Therefore, to declare a recursive function, we must uselet rec
  instead:
let rec factorial (n : int) : int =
  if n = 0 then
    1
  else
    n * factorial (n - 1)
;;
print_string ("factorial 5 = " ^ string_of_int (factorial 5) ^ "\n")Printing strings in this manner is a very poor way to test code. You'll do better by writing test cases as follows:
TEST "testing factorial 5" =
  factorial 5 = 120
TEST "testing factorial 8" =
  factorial 8 = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8The TEST notation is not standard OCaml, but a handy syntax extension
  that we use extensively in this course. The course software will take
  care of linking to the syntax extension for you.
For this course, you should use the cs691f build tool to
  compile programs and run tests. This program is a thin wrapper around the
  OCaml's own build system that links to libraries and extensions
  that we use in this course. If you want to look under the hood, the code
  is 
  online
  and in OCaml.
Place the declaration of factorial and its test cases, all of which
  appear above, in a new file called tutorial.ml. Then, compile, run,
  and test using the cs691f tool:
$ cs691f compile tutorial $ cs691f run tutorial $ cs691f test tutorial
You should not get any errors.
Write a function, seconds_since_midnight h m s, which returns 
	the number of seconds elapsed since midnight. Your function should have the
	following type.
val seconds_since_midnight : int -> int -> int -> intlet seconds_since_midnight (hours : int) (mins : int) (secs : int) : int =
  secs + 60 * (mins + 60 * hours)
TEST "midnight" = seconds_since_midnight 0 0 0 = 0
TEST "12:59:59PM" = seconds_since_midnight 23 59 59 = 86399
TEST "1:30AM" = seconds_since_midnight 1 30 0 = 3600 + 30 * 60Write a function, fibonacci n, which compute the nth
  Fibonacci number. The function should have the following type:
val fibonacci : int -> intlet rec fibonacci n =
  if n = 0 then
    0
  else if n = 1 then
    1
  else fibonacci (n - 1) + fibonacci (n - 2)
TEST "fib 2" = 
  fibonacci 2 = 1
TEST "fib 7" = 
  fibonacci 7 = 13The previous section covered let declarations. This section introduces type declarations. Here is an example:
type point =
    Point2D of int * intThis type declaration introduces a type called point. It has one 
constructor called Point2D that takes two arguments, both
integers. Type names must begin with a lowercase letter and constructor names must
begin with an uppercase letter.
Given this declaration, we can use the constructor to create new points:
let origin : point = Point2D (0, 0)
let pt1 : point = Point2D (10, 20)
let pt2 : point = Point2D (-40, 50)Above, the parentheses and commas are required: the constructor name must be followed by a comma-separated list of arguments enclosed in parentheses.
Define a type, time, which holds the hour, minute,
	and second as separate values.
type time = Time of int * int * intGiven a point value, we can use pattern matching to extract its components, as these functions do:
let double_point (p : point) : point =
  match p with
    Point2D (x, y) -> Point2D (2 * x, 2 * y)
let add_point (p1 : point) (p2 : point) : point =
  match (p1, p2) with
    (Point2D (x1, y1), Point2D (x2, y2)) -> Point2D (x1 + x2, y1 + y2)
let string_of_point (p : point) : string =
  match p with
    Point2D (x, y) -> "<" ^ string_of_int x ^ ", " ^ string_of_int y ^ ">"
In the following several exercises, you will use pattern matching to write functions that manipulate points. The OCaml manual has a section on integer arithmetic that will be helpful.
Write a function seconds_since_midnight2 with the
	following type:
val seconds_since_midnight2 : time -> intlet seconds_since_midnight2 (t : time) : int = 
  match t with
  | Time (hours, mins, secs) -> secs + 60 * (mins + 60 * hours)Write a function seconds_to_time t, which takes the seconds
	elapsed since midnight as its argument and returns the coresponding time.
val seconds_to_time : int -> timelet seconds_to_time (n : int) : time =
  let secs = n mod 60 in
  let n = (n - secs) / 60 in
  let mins = n mod 60 in
  let n = (n - secs) / 60 in
  let hours = n in
  Time (hours, mins, secs)
TEST = seconds_to_time 0 = Time (0, 0, 0)
TEST = seconds_to_time 86399 = Time (23, 59, 59)
TEST = seconds_to_time 86400 = Time (24, 0, 0)Write a function time_diff t1 t2, which calculates
	the number of seconds that have elapsed between t1 and
	t2:
val time_diff : time -> time -> intlet time_diff (t1 : time) (t2 : time) : int =
  seconds_since_midnight2 t1 - seconds_since_midnight2 t2
TEST = let t = Time (1, 1, 1) in time_diff t t = 0
TEST = time_diff (Time (23, 59, 59)) (Time (0, 0, 0)) = 86399Write a function tick t, which increments t by
 	one second and returns the new time:
val tick : time -> timelet tick (t : time) : time =
  seconds_to_time (1 + seconds_since_midnight2 t)
TEST = tick (Time (0, 0, 59)) = Time (0, 1, 0)
TEST = tick (Time (1, 59, 59)) = Time (2, 0, 0)
TEST = tick (Time (23, 59, 59)) = Time (24, 0, 0)For this part of the tutorial, we will work with a type declaration for lists of integers. There are two kinds of lists: the empty list and lists that have a single integer and a a reference to the rest of the list. We can specify the shape of lists using a type declaration with two constructors:
type intlist =
  | Cons of int * intlist
  | EmptyFor example, here is a list of numbers from -1 through 4:
let from_minus_1_to_4 =
  Cons (-1, Cons (0, Cons (1, Cons (2, Cons (3, (Cons (4, Empty)))))))We can declare list processing functions using the same constructs we used to write date processing functions. However, since lists are recursively defined, most interesting list processing functions need to be recursive, too. For example, here is a function that calcululates the length of a list:
let rec length (lst : intlist) : int =
  match lst with
  | Empty -> 0
  | Cons (first, rest) -> 1 + length rest
TEST = length Empty = 0
TEST = length from_minus_1_to_4 = 6Write a function all_positive lst, which returns true
	if all the integers in lst are positive.
val all_positive : intlist -> boollet rec all_positive (lst : intlist) : bool =
  match lst with
  | Empty -> true
  | Cons (n, rest) -> n > 0 && all_positive rest
TEST = all_positive (Cons (1, Empty)) = true
TEST = all_positive (Cons (-1, Empty)) = false
TEST = all_positive (Cons (1, Cons (-1, Empty))) = falseWrite a function all_even lst, which returns true
	if all the integers in lst are even numbers.
val all_even : intlist -> boollet rec all_even (lst : intlist) : bool =
  match lst with
  | Empty -> true
  | Cons (n, rest) -> n mod 2 = 0 && all_even rest
TEST = all_even (Cons (10, (Cons (2, Empty)))) = true
TEST = all_even (Cons (9, (Cons (1, Empty)))) = false
TEST = all_even Empty = trueWrite the function is_sorted lst to determine if the
	integers in lst are in sorted (ascending).
val is_sorted : intlist -> boolHint: You will need to write a recursive helper function.
let rec is_sorted_helper (prev : int) (lst : intlist) : bool =
  match lst with
  | Empty -> true
  | Cons (n, rest) -> prev <= n && is_sorted_helper n rest
let is_sorted (lst : intlist) : bool =
  match lst with
  | Empty -> true
  | Cons (n, rest) -> is_sorted_helper n rest
TEST = is_sorted (Cons (1, Cons (2, Cons (3, Empty)))) = true
TEST = is_sorted (Cons (1, Cons (1, Cons (3, Empty)))) = true
TEST = is_sorted (Cons (1, Cons (3, Cons (2, Empty)))) = falseWrite the function insert_sorted n lst, which inserts 
  n into the sorted list lst and preserves the
  sort-order.
(* Assumes that [is_sorted lst] holds. *)
let rec insert_sorted (n : int) (lst : intlist) : intlist =
  match lst with
  | Empty -> Cons (n, Empty)
  | Cons (m, rest) ->
    (match n <= m with
     | true -> Cons (n, Cons (m, rest))
     | false -> Cons (m, insert_sorted n rest))
TEST = insert_sorted 5 Empty = Cons (5, Empty)
TEST = 
  insert_sorted 1 (Cons (0, Cons (2, Empty))) = 
  Cons (0, Cons (1, Cons (2, Empty)))
TEST = insert_sorted 10 (Cons (10, Empty)) = Cons (10, Cons (10, Empty))Write the insertion_sort function, using
  insert_sorted as a helper.
val insertion_sort : intlist -> intlistlet rec insertion_sort (lst : intlist) : intlist = 
  match lst with
  | Empty -> Empty
  | Cons (n, rest) -> insert_sorted n (insertion_sort rest)
TEST = insertion_sort (Cons (3, Cons (2, Cons (1, Empty)))) =
       Cons (1, Cons (2, Cons (3, Empty)))For this part of the tutorial, you will write an evaluator and pretty-printer for simple arithmetic expressions—the simplest of interpreters. Notably, this interpreter does not use any OCaml concept beyond those introduced above.
For the exercises below, use the following type declaration that represents arithmetic expressions.
type exp =
  | Int of int
  | Add of exp * exp
  | Mul of exp * expEncode the following arithmetic expressions as exps:
  	
let ex1 = Add (Int 10, Int 5)
let ex2 = Mul (Add (Int 2, Int 3), Int 5)
let ex3 = Mul ((Mul (Int 3, Int 0)), Mul (Int 3, Int 5))Write the function eval e, which reduces expressions to
	integer values:
val eval : exp -> intlet rec eval (e : exp) : int = match e with
  | Int n -> n
  | Add (e1, e2) -> eval e1 + eval e2
  | Mul (e1, e2) -> eval e1 * eval e2
TEST = eval (Add (Int 10, Int 5)) = 15
TEST = eval (Mul (Add (Int 2, Int 3), Int 5)) = (2 + 3) * 5
TEST = eval (Mul ((Mul (Int 3, Int 0)), Mul (Int 3, Int 5))) = 0Write the function print e, which returns a string
	representing e:
val print : exp -> stringThe string should print arithmetic operators using infix notation and properly parenthesize expressions. For example, here are some tests:
TEST = print (Add (Int 10, Int 5)) = "(10 + 5)"
TEST = print (Mul (Add (Int 2, Int 3), Int 5)) = "((2 + 3) * 5)"
TEST = print (Mul ((Mul (Int 3, Int 0)), Mul (Int 3, Int 5))) = "((3 * 0) * (3 * 5))"Use the ^ operator to concatenate strings and the string_of_int function.
let rec print (e : exp) : string = match e with
  | Int n -> string_of_int n
  | Add (e1, e2) -> "(" ^ print e1 ^ " + " ^ print e2 ^ ")"
  | Mul (e1, e2) -> "(" ^ print e1 ^ " * " ^ print e2 ^ ")"The print function that you wrote above may be naive
	about how it prints parentheses. For example, 1 + 2 * 3
	is usually interpreted as 1 + (2 * 3) because the *
	operator + operator.
	Write the pretty_print e function, which prints parentheses
	only when necessary:
val pretty_print : exp -> stringpp cxt e,
	where e is the expression to print and cxt identifies
	the shape of the immediately surrounding context.
type cxt = 
  | TopCxt (* top-level expression *)
  | MulCxt (* [_ * x] or [x * _] *)
  | AddCxt  (* [_ + x] or [x + _] *)
let rec pp (enclosing : cxt) (e : exp) : string =
  match e with
  | Int n -> string_of_int n
  | Add (e1, e2) -> 
    let inner = (pp AddCxt e1) ^ " + " ^ (pp AddCxt e2) in
    (match enclosing with
     | MulCxt -> "(" ^ inner ^ ")"
     | _ -> inner)
  | Mul (e1, e2) ->
    (pp MulCxt e1) ^ " * " ^ (pp MulCxt e2)
let pretty_print (e : exp) : string = pp TopCxt e
TEST = pretty_print (Add (Int 10, Int 5)) = "10 + 5"
TEST = pretty_print (Mul (Add (Int 2, Int 3), Int 5)) = "(2 + 3) * 5"
TEST =
  pretty_print (Mul ((Mul (Int 3, Int 0)), Mul (Int 3, Int 5))) = "3 * 0 * 3 * 5"