...
 
Commits (6)
This diff is collapsed.
let todo _ = failwith "TODO"
(* 7.5 type definitions *)
type rat = int * int (* num, denom *)
type var = string (* new *)
type binary_op = Add | Sub | Mul | Div
type unary_op = Neg
type expr = Const of rat
| UnOp of unary_op * expr
| BinOp of binary_op * expr * expr
| Var of var (* new *)
| Func of var * expr (* new *)
| Bind of var * expr * expr (* new *)
| App of expr * expr (* new *)
| Ite of expr * expr * expr (* new *)
type value = Rat of rat | Fun of var * state * expr (* new *)
and state = var -> value option (* new *)
(* 7.6 type definitions *)
type graph = (int * float * int) list
(*****************************************************************************)
(**************************** HOMEWORK STARTS HERE ***************************)
(*****************************************************************************)
(* Assignment 7.4 [7 points] *)
let f1 = todo
let f2 = todo
let f3 = todo
let f4 = todo
let f5 = todo
let f6 = todo
let f7 = todo
(*****************************************************************************)
(* Assignment 7.5 [7 points] *)
let rec eval_expr (s : state) (e : expr) : value =
match e with Const c -> Rat c
| UnOp (Neg, e) -> (match eval_expr s e with
| Rat (n, d) -> Rat (-n, d)
| _ -> failwith "invalid type")
| BinOp (op, e1, e2) ->
(match eval_expr s e1, eval_expr s e2 with
| Rat (n1, d1), Rat (n2, d2) ->
(match op with
| Add -> Rat (n1*d2+n2*d1,d1*d2)
| Sub -> Rat (n1*d2-n2*d1,d1*d2)
| Mul -> Rat (n1*n2,d1*d2)
| Div -> Rat (n1*d2,d1*n2))
| _ -> failwith "invalid type")
(* TODO: continue here *)
| _ -> todo ()
(*****************************************************************************)
(* assignment 7.6 [6 points] *)
let mst = todo
(*****************************************************************************)
(***************************** HOMEWORK ENDS HERE ****************************)
(*****************************************************************************)
(* example inputs, you may use them to test your implementations,
but [do not change] *)
(*
_a + _b
*)
let a75_ex1 = BinOp (Add, Var "_a", Var "_b")
(*
let x = 2/7 in x
*)
let a75_ex2 = Bind ("x", Const (2, 7), Var "x")
(*
if 3/4 then 1/2 else 2/1
*)
let a75_ex3 = Ite (Const (3, 4), Const (1, 2), Const (2, 1))
(*
if 1/4 * 0/1 then 1/2 else 2/1
*)
let a75_ex4 = Ite (BinOp (Mul, Const (1, 4), Const (0, 1)), Const (1, 2), Const (2, 1))
(*
(fun z -> 1/3 - z)
*)
let a75_ex5 = Func ("z", BinOp (Sub, Const (1, 3), Var "z"))
(*
let f = fun x -> x * x in
f (1/2 - 1/4)
*)
let a75_ex6 = Bind ("f", Func ("x", BinOp (Mul, Var "x", Var "x")), App (Var "f", BinOp (Sub, Const (1, 2), Const (1, 4))))
(*
let add = fun x -> fun y -> x + y in
let x = 2/3 in
add x 4/3
*)
let a75_ex7 = Bind ("add", Func ("x", Func ("y", BinOp (Add, Var "x", Var "y"))), Bind ("x", Const (2,3), App (App (Var "add", Var "x"), Const (4, 3))))
(*
(let x = 2/1 in fun a -> let x = a + x in x * x) 10/2
*)
let a75_ex8 = App (Bind ("x", Const (2,1), Func ("a", Bind ("x", BinOp (Add, Var "a", Var "x"), BinOp (Mul, Var "x", Var "x")))), Const (10, 2))
let a76_ex1 = [0,1.,1; 0,4.,2; 1,2.,2; 1,1.,3; 2,3.,3]
let a76_ex2 = [0,4.,1; 0,4.,7; 1,8.,2; 1,11.,7; 2,7.,3; 2,4.,5; 2,2.,8; 3,9.,4; 3,14.,5; 4,10.,5; 5,2.,6; 6,1.,7; 6,6.,8; 7,7.,8;]
(*****************************************************************************)
(* TESTS [do not change] *)
let (=.) a b = (abs_float (a -. b)) < 0.001
let print_mst_for t =
print_endline ("[" ^ (String.concat "; " (List.map (fun (s,w,d) -> "(" ^ (string_of_int s) ^ "," ^ (string_of_float w) ^ "," ^ (string_of_int d) ^ ")") t)) ^ "]")
let simp (n,d) =
let k, n = if n < 0 then -1, -n else 1, n in
let k, d = if d < 0 then -k, -d else k, d in
let rec gcd a b =
if b = 0 then a else gcd b (a mod b)
in
let g = gcd n d in
(k * n / g, d / g)
let test_ee p e =
let s = fun r -> if r = "_a" then Some (Rat (1,3)) else if r = "_b" then Some (Rat (1, 6)) else Some (Rat (0, 1)) in
match e, eval_expr s p with
| Rat (en, ed), Rat (pn, pd) -> (en,ed) = simp (pn, pd)
| Fun (ea, _, ed), Fun (pa, _, pd) -> ea = pa && ed = pd
| _, _ -> false
let test_mst g e =
let sort_t l = List.map (fun (s,w,d) -> if d < s then (d, w, s) else (s, w, d)) l |>
List.sort (fun (s1,_,d1) (s2,_,d2) -> if s1 = s2 then compare d1 d2 else compare s1 s2) in
let t1 = (sort_t (mst g)) in
let t2 = (sort_t e) in
let rec cmp l1 l2 = match l1, l2 with [],[] -> true
| (s1,w1,d1)::xs, (s2,w2,d2)::ys -> s1 = s2 && d1 = d2 && w1 =. w2 && cmp xs ys
| _, _ -> false
in
(* print_mst_for t1; print_mst_for t2; *)
cmp t1 t2
let tests = [
(* tests for 7.4 *)
__LINE_OF__ (fun () -> (List.fold_left f1 0 ["ab"; "xx"; "ab"; "u"; "iuw"; "bb"]) = 6);
__LINE_OF__ (fun () -> (List.fold_left f2 [] [[1;2;3]; [0]; [7;9;1;3]; []; [1]]) = [7;9;1;3]);
__LINE_OF__ (fun () -> (List.fold_left f3 [] [(1,2); (3,4); (5,6)]) = [(2,1); (4,3); (6,5)]);
__LINE_OF__ (fun () -> (List.fold_left f4 [] ['a';'b';'c';'d';'e';'f';'g']) = ['g';'e';'c';'a';'b';'d';'f']);
__LINE_OF__ (fun () -> let g = List.fold_left f5 (fun _ -> 0) [('a',3); ('z', -9); ('d', 18)] in (g 'a' = 3) && (g 'd' = 18) && (g 'z' = -9));
__LINE_OF__ (fun () -> (List.fold_left f6 [0] [(fun x -> x + 3); (fun x -> x * x); (fun x -> x * -4)]) = [-36;9;3;0]);
__LINE_OF__ (fun () -> (List.fold_left f7 (-3) [6;-2;3]) = 102036672);
(* tests for 7.5 *)
__LINE_OF__ (fun () -> test_ee a75_ex1 (Rat (1, 2)));
__LINE_OF__ (fun () -> test_ee a75_ex2 (Rat (2, 7)));
__LINE_OF__ (fun () -> test_ee a75_ex3 (Rat (1, 2)));
__LINE_OF__ (fun () -> test_ee a75_ex4 (Rat (2, 1)));
__LINE_OF__ (fun () -> test_ee a75_ex5 (Fun ("z", (fun _ -> None), BinOp (Sub, Const (1, 3), Var "z"))));
__LINE_OF__ (fun () -> test_ee a75_ex6 (Rat (1, 16)));
__LINE_OF__ (fun () -> test_ee a75_ex7 (Rat (2, 1)));
__LINE_OF__ (fun () -> test_ee a75_ex8 (Rat (49, 1)));
(* tests for 7.6 *)
__LINE_OF__ (fun () -> test_mst a76_ex1 [0,1.,1; 1,2.,2; 1,1.,3]);
__LINE_OF__ (fun () -> test_mst a76_ex2 [0,4.,1; 0,4.,7; 2,7.,3; 2,4.,5; 2,2.,8; 3,9.,4; 5,2.,6; 6,1.,7]);
]
let () =
let rec input_lines ch =
(try Some (input_line ch) with _ -> None) (* catch stupid EOF exception *)
|> function Some line -> line :: input_lines ch | None -> []
in
let lines = input_lines (open_in __FILE__) in
let open List in
let open Printf in
let fail l =
let line = nth lines (l-1) in
let test = String.sub line 25 (String.length line - 27) in
printf "test \027[31;m%s\027[0;m (line %d) failed!\n" test l;
in
let test (l, t) =
let ok = try t () with e -> print_endline (Printexc.to_string e); false in
if not ok then fail l;
ok
in
let passed = filter (fun x -> x) (map test tests) in
printf "passed %d/%d tests\n" (length passed) (length tests)
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.1 (P) Partial Application\n",
"\n",
"Types of n-ary functions are denoted as `arg_1 -> ... -> arg_n -> ret` in OCaml. \n",
"\n",
"1) Discuss, why this notation is indeed meaningful.\n",
"\n",
"2) Give the types of these expressions and discuss to what they evaluate:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let a (* : todo *) = (fun a b c -> c (a + b)) 3 \n",
"\n",
"let b (* : todo *) = (fun a b -> (+) b) \n",
"\n",
"let c (* : todo *) = (fun a b c -> b (c a) :: [a]) \"x\" \n",
"\n",
"let d (* : todo *) = (fun a b -> List.fold_left b 1 (List.map ( * ) a))\n",
"\n",
"let e (* : todo *) = (let x = List.map in x (<))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.2 (P) Tail Recursion\n",
"\n",
"1) Check which of the following functions are tail recursive:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec f a = match a with [] -> a \n",
" | x::xs -> (x+1)::f xs\n",
"\n",
"let rec g a b = if a = b then 0 \n",
" else if a < b then g (a+1) b \n",
" else g (a-1) b\n",
"\n",
"let rec h a b c = if b then h a (not b) (c * 2) \n",
" else if c > 1000 then a \n",
" else h (a+2) (not b) c * 2\n",
"\n",
"let rec i a = function [] -> a \n",
" | x::xs -> i (i (x,x) [x]) xs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) Write tail recursive versions of the following functions (without changing their types):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec fac n = if n < 2 then 1 \n",
" else n * fac (n-1)\n",
"\n",
"let rec remove a = function [] -> []\n",
" | x::xs -> if x = a then remove a xs else x::remove a xs\n",
" \n",
"let rec partition f l = match l with [] -> [],[]\n",
" | x::xs -> let a,b = partition f xs in\n",
" if f x then x::a,b else a,x::b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let fac n = failwith \"todo\"\n",
" \n",
"let remove a l = failwith \"todo\"\n",
"\n",
"let partition f l = failwith \"todo\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.3 (P) Lazy Lists\n",
"\n",
"Infinite data structures (e.g. lists) can be realized using the concept of **lazy evaluation**. Instead of constructing the entire data structure immediately, we only construct a small part and keep us a means to construct more on demand. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"type 'a llist = Cons of 'a * (unit -> 'a llist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1) Implement the function `lnat : int -> int llist` that constructs the list of all natural numbers starting at the given argument.\n",
"\n",
"2) Implement the function `lfib : unit -> int llist` that constructs a list containing the Fibonacci sequence. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let lnat i = failwith \"todo\"\n",
"\n",
"let lfib () = failwith \"todo\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Implement the function `ltake : int -> 'a llist -> 'a list` that returns the first $n$ elements of the list.\n",
"\n",
"4) Implement the function `lfilter : ('a -> bool) -> 'a llist -> 'a llist` to filter those elements from the list that do not satisfy the given predicate. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let ltake n l = failwith \"todo\"\n",
"\n",
"let lfilter f l = failwith \"todo\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.4 (P) Little Helpers\n",
"\n",
"Consider the following functions. \n",
"\n",
"* `(%) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b`\n",
"* `(@@) : ('a -> 'b) -> 'a -> 'b`\n",
"* `(|>) : 'a -> ('a -> 'b) -> 'b`\n",
"\n",
"1) Try to find their implementation just from the types:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let (%) = failwith \"todo\"\n",
"\n",
"let (@@) = failwith \"todo\"\n",
"\n",
"let (|>) = failwith \"todo\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) When is it possible to derive the implementation from the type?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Give an example where these operators could be used."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "OCaml 4.07.0",
"language": "OCaml",
"name": "ocaml-jupyter"
},
"language_info": {
"codemirror_mode": "text/x-ocaml",
"file_extension": ".ml",
"mimetype": "text/x-ocaml",
"name": "OCaml",
"nbconverter_exporter": null,
"pygments_lexer": "OCaml",
"version": "4.07.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.1 (P) Partial Application\n",
"\n",
"Types of n-ary functions are denoted as `arg_1 -> ... -> arg_n -> ret` in OCaml. \n",
"\n",
"1) Discuss, why this notation is indeed meaningful.\n",
"\n",
"An n-ary function can be considered as an unary function that returns an (n-1)-ary function. Every function with multiple arguments can thus be treated as a sequence of applications of unary functions: `arg_1 -> (arg_2 -> ... (arg_n -> ret) ... )`. In fact, a definition `let foo a b c = a + b + c` is just a more convenient way to write `let foo = fun a -> fun b -> fun c -> a + b + c`.\n",
"\n",
"2) Give the types of these expressions and discuss to what they evaluate:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let a : int -> (int -> 'a) -> 'a = (fun a b c -> c (a + b)) 3 \n",
" (* fun b c -> c (3 + b) *)\n",
"\n",
"let b : 'a -> int -> int -> int = (fun a b -> (+) b) \n",
" (* fun a b i1 -> b + i1 *)\n",
"\n",
"let c : ('a -> string) -> (string -> 'a) -> string list\n",
" = (fun a b c -> b (c a) :: [a]) \"x\" \n",
" (* fun b c -> [b (c \"x\"); \"x\"] *)\n",
"\n",
"let d : int list -> (int -> (int -> int) -> int) -> int\n",
" = (fun a b -> List.fold_left b 1 (List.map ( * ) a))\n",
" (* fun a b -> List.fold_left b 1 (List.map ( * ) a ) *)\n",
"\n",
"let e : 'a list -> ('a -> bool) list = (let x = List.map in x (<))\n",
" (* fun l -> List.map (<) l *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.2 (P) Tail Recursion\n",
"\n",
"1) Check which of the following functions are tail recursive:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec f a = match a with [] -> a \n",
" | x::xs -> (x+1)::f xs\n",
"\n",
"let rec g a b = if a = b then 0 \n",
" else if a < b then g (a+1) b \n",
" else g (a-1) b\n",
"\n",
"let rec h a b c = if b then h a (not b) (c * 2) \n",
" else if c > 1000 then a \n",
" else h (a+2) (not b) c * 2\n",
"\n",
"let rec i a = function [] -> a \n",
" | x::xs -> i (i (x,x) [x]) xs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) Write tail recursive versions of the following functions (without changing their types):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec fac n = if n < 2 then 1 \n",
" else n * fac (n-1)\n",
"\n",
"let rec remove a = function [] -> []\n",
" | x::xs -> if x = a then remove a xs else x::remove a xs\n",
" \n",
"let rec partition f l = match l with [] -> [],[]\n",
" | x::xs -> let a,b = partition f xs in\n",
" if f x then x::a,b else a,x::b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let fac n = \n",
" let rec impl n acc = if n < 2 then acc \n",
" else impl (n-1) (acc * n)\n",
" in\n",
" impl n 1\n",
" \n",
"let remove a l = \n",
" let rec impl l acc = \n",
" match l with [] -> acc\n",
" | x::xs -> if x = a then impl xs acc \n",
" else impl xs (x::acc)\n",
" in\n",
" List.rev (impl l [])\n",
"(* or: *)\n",
"let remove a l = List.rev (List.fold_left \n",
" (fun acc x -> if x = a then acc else x::acc) [] l)\n",
"\n",
"let partition f l = \n",
" let rec impl l (a,b) =\n",
" match l with [] -> (a,b)\n",
" | x::xs -> impl xs (if f x then x::a,b else a,x::b)\n",
" in\n",
" let r = impl l ([],[]) in\n",
" List.rev (fst r), List.rev (snd r)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.3 (P) Lazy Lists\n",
"\n",
"Infinite data structures (e.g. lists) can be realized using the concept of **lazy evaluation**. Instead of constructing the entire data structure immediately, we only construct a small part and keep us a means to construct more on demand. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"type 'a llist = Cons of 'a * (unit -> 'a llist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1) Implement the function `lnat : int -> int llist` that constructs the list of all natural numbers starting at the given argument.\n",
"\n",
"2) Implement the function `lfib : unit -> int llist` that constructs a list containing the Fibonacci sequence. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec lnat i = Cons (i, (fun () -> lnat (i + 1)))\n",
"\n",
"let lfib () = \n",
" let rec impl a b = Cons (a, fun () -> impl b (a+b))\n",
" in\n",
" impl 0 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Implement the function `ltake : int -> 'a llist -> 'a list` that returns the first $n$ elements of the list.\n",
"\n",
"4) Implement the function `lfilter : ('a -> bool) -> 'a llist -> 'a llist` to filter those elements from the list that do not satisfy the given predicate. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec ltake n (Cons (h, t)) = \n",
" if n <= 0 then [] else h::ltake (n-1) (t ())\n",
" \n",
"let rec lfilter f (Cons (h, t)) = \n",
" if f h then Cons (h, fun () -> lfilter f (t ()))\n",
" else lfilter f (t ())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 8.4 (P) Little Helpers\n",
"\n",
"Consider the following functions. \n",
"\n",
"* `(%) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b`\n",
"* `(@@) : ('a -> 'b) -> 'a -> 'b`\n",
"* `(|>) : 'a -> ('a -> 'b) -> 'b`\n",
"\n",
"1) Try to find their implementation just from the types:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let (%) f g x = f (g x)\n",
"\n",
"let (@@) f x = f x\n",
"\n",
"let (|>) x f = f x"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) When is it possible to derive the implementation from the type?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Assuming we use no side-effects:\n",
"For types `x` and `y`, a pure function `x -> y` has `|x| * |y|` possible implementations (where `|x|` indicates the number of values of type `x`).\n",
"Example for a function `bool -> bool`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let implementations = [\n",
" (fun _ -> true);\n",
" (fun _ -> false);\n",
" (fun x -> x);\n",
" (fun x -> not x);\n",
"]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since a polymorphic type could be any type (e.g. also `unit`), we don't know about its values, and since we can't inspect them, we also can't match on them. Therefore, for pure functions that don't have any concrete type in the signature, there is only one possible implementation."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Give an example where these operators could be used."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"List.map (string_of_int % fst) [(1,'a'); (2,'b'); (3,'c')]\n",
"(* instead of\n",
"List.map (fun x -> string_of_int (fst x)) [(1,'a'); (2,'b'); (3,'c')]\n",
"*)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"String.concat \"\" @@ List.map string_of_int \n",
" @@ List.map fst [(1,'a'); (2,'b'); (3,'c')]\n",
"(* instead of\n",
"String.concat \"\" (List.map string_of_int \n",
" (List.map fst [(1,'a'); (2,'b'); (3,'c')]))\n",
"*)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"List.map fst [(1,'a'); (2,'b'); (3,'c')] \n",
" |> List.map string_of_int |> String.concat \"\"\n",
"(* instead of\n",
"String.concat \"\" (List.map string_of_int \n",
" (List.map fst [(1,'a'); (2,'b'); (3,'c')]))\n",
"*)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "OCaml 4.07.0",
"language": "OCaml",
"name": "ocaml-jupyter"
},
"language_info": {
"codemirror_mode": "text/x-ocaml",
"file_extension": ".ml",
"mimetype": "text/x-ocaml",
"name": "OCaml",
"nbconverter_exporter": null,
"pygments_lexer": "OCaml",
"version": "4.07.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
let todo _ = failwith "todo"
(* type definitions *)
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
type 'a ltree = LNode of 'a * (unit -> 'a ltree) * (unit -> 'a ltree)
(*****************************************************************************)
(**************************** HOMEWORK STARTS HERE ***************************)
(*****************************************************************************)
(* Assignment 8.5 [3 Points] *)
let interleave3 = todo
(*****************************************************************************)
(* Assignment 8.6 [4 Points] *)
let lagrange = todo
(*****************************************************************************)
(* Assignment 8.7 [6 Points] *)
let insert = todo
let string_of_tree = todo
let inorder_list = todo
(*****************************************************************************)
(* Assignment 8.8 [7 Points] *)
let layer_tree = todo
let interval_tree = todo
let rational_tree = todo
let top = todo
let map = todo
let find = todo
(*****************************************************************************)
(**************************** END OF HOMEWORK ********************************)
(*****************************************************************************)
(* example inputs, you may use them to test your implementations,
but [do not change] *)
type 'a a85_test_input = { l1 : 'a list; l2 : 'a list; l3 : 'a list }
let a85_ex1 = { l1 = [0;1;2]; l2 = [10;11;12]; l3 = [20;21;22] }
let a85_ex2 = { l1 = ['a';'b']; l2 = ['A';'B';'C';'D']; l3 = ['!'] }
let a85_ex3 = { l1 = []; l2 = []; l3 = [] }
type a86_test_input = { points : (float * float) list; poly : float -> float }
let a86_ex1 = { points=[100.,231.]; poly=fun x -> 231. }
let a86_ex2 = { points=[100.,231.; 200.,12.]; poly=fun x -> 450. -. 2.19 *. x }
let a86_ex3 = { points=[100.,231.; 200.,12.; 300.,382.5]; poly=fun x -> 0.029475 *. x *. x -. 11.0325 *. x +. 1039.5 }
let a88_ex1 = let rec b () = LNode ('a', b, b) in b ()
let a88_ex2 = let rec b s () = LNode (s, b (0::s), b (1::s)) in b [] ()
let a88_ex3 = let rec b i () = LNode (i * i, b (i+1), b (i+1)) in b 0 ()
let a88_ex4 = let rec b x () = LNode (x, b (x * 10), b (x + 10)) in b 0 ()
let a88_ex5 = let rec b x () = LNode (x, b (x * 10), b (x + 10)) in b 1000 ()
(*****************************************************************************)
(* TESTS [do not change] *)
let (=.) a b = (abs_float (a -. b)) < 0.001
let (=~) a b =
let trimmed s = String.split_on_char ' ' s |> List.filter (fun x -> (String.length x) > 0) |> String.concat "" in
String.equal (trimmed a) (trimmed b)
let is_interleave3_tailrec () =
let l = List.init 1000000 (fun _ -> 1) in
try ignore(interleave3 l l l); ignore(interleave3 [] l []); true with Stack_overflow -> false
let compare_polys (p : float -> float) (ex : a86_test_input) : bool =
(List.for_all (fun (x,y) -> (p x) =. y) ex.points) &&
(List.init 10 (fun x -> 37.5 *. float_of_int x) |> List.for_all (fun x -> (p x) =. (ex.poly x)))
let insert_ vs cmp t =
List.fold_left (fun t v -> insert v cmp t) t vs
let is_inorder_list_tailrec () =
ignore(inorder_list Empty);
(* TODO: Tutors will check *)
(* let l = List.init 10000 (fun x -> x) in
let t = insert_ l compare Empty in
try ignore(inorder_list t); true with Stack_overflow -> false *)
true
let check_layer_tree r t =
let rec impl n r (LNode (x, fl, fr)) =
if n <= 0 then true else r = x && (impl (n-1) (r+1) (fl ())) && (impl (n-1) (r+1) (fr ()))
in
impl 4 r t
let check_interval_tree i t =
let rec impl n (l,h) (LNode ((l',h'), fl, fr)) =
if n <= 0 then true else (l =. l') && (h =. h') && (impl (n-1) (l, (l+.h)/.2.) (fl ())) && (impl (n-1) ((l+.h)/.2., h) (fr ()))
in
impl 4 i t
let check_rational_tree t =
let rec impl n (a,b) (LNode ((a',b'), fl, fr)) =
if n <= 0 then true else (a = a') && (b = b') && (impl (n-1) (a, b+1) (fl ())) && (impl (n-1) (a+1, b) (fr ()))
in
impl 4 (0,0) t
let rec compare_ltrees n (LNode (x1, lf1, rf1)) (LNode (x2, lf2, rf2)) =
if n <= 0 then true else x1 = x2 && (compare_ltrees (n-1) (lf1 ()) (lf2 ())) && (compare_ltrees (n-1) (rf1 ()) (rf2 ()))
let tests = [
(* tests for 8.5 *)
__LINE_OF__ (fun () -> (interleave3 a85_ex1.l1 a85_ex1.l2 a85_ex1.l3) = [0;10;20;1;11;21;2;12;22]);
__LINE_OF__ (fun () -> (interleave3 a85_ex2.l1 a85_ex2.l2 a85_ex2.l3) = ['a';'A';'!';'b';'B';'C';'D']);
__LINE_OF__ (fun () -> (interleave3 a85_ex3.l1 a85_ex3.l2 a85_ex3.l3) = []);
__LINE_OF__ (fun () -> is_interleave3_tailrec ());
(* tests for 8.6 *)
__LINE_OF__ (fun () -> (let l = lagrange a86_ex1.points in compare_polys l a86_ex1));
__LINE_OF__ (fun () -> (let l = lagrange a86_ex2.points in compare_polys l a86_ex2));
__LINE_OF__ (fun () -> (let l = lagrange a86_ex3.points in compare_polys l a86_ex3));
(* tests for 8.7 *)
__LINE_OF__ (fun () -> (insert 3 compare Empty) = Node (3, Empty, Empty));
__LINE_OF__ (fun () -> (insert 3 compare (Node (6, Empty, Empty))) = Node (6, Node (3, Empty, Empty), Empty));
__LINE_OF__ (fun () -> (insert_ [1;3;8;2;7;4;9] compare Empty) = Node (1, Empty, Node (3, Node (2, Empty, Empty), Node (8, Node (7, Node (4, Empty, Empty), Empty), Node (9, Empty, Empty)))));
__LINE_OF__ (fun () -> (insert 3 (fun a b -> b - a) (Node (6, Empty, Empty))) = Node (6, Empty, Node (3, Empty, Empty)));
__LINE_OF__ (fun () -> (insert_ [(3,2);(10,-2);(18,20)] (fun (a1,a2) (b1,b2) -> compare (a1 + a2) (b1 + b2)) Empty) = Node ((3,2), Empty, Node ((10,-2), Empty, Node ((18,20), Empty, Empty))));
__LINE_OF__ (fun () -> (string_of_tree (fun _ -> "") Empty) = "Empty");
__LINE_OF__ (fun () -> (string_of_tree (fun _ -> "xx") (Node (2.5, Empty, Empty))) =~ "Node (xx, Empty, Empty)");
__LINE_OF__ (fun () -> (string_of_tree string_of_int (Node (3, Empty, Node (1, Empty, Empty)))) =~ "Node (3, Empty, Node (1, Empty, Empty))");
__LINE_OF__ (fun () -> (inorder_list Empty) = []);
__LINE_OF__ (fun () -> (inorder_list (Node (2, Node (1, Empty, Empty), Node (3, Empty, Empty)))) = [1;2;3]);
__LINE_OF__ (fun () -> (inorder_list (Node (1, Empty, Node (3, Node (2, Empty, Empty), Node (8, Node (7, Node (4, Empty, Empty), Empty), Node (9, Empty, Empty)))))) = [1;2;3;4;7;8;9]);
__LINE_OF__ (fun () -> (is_inorder_list_tailrec ()));
(* tests for 8.8 *)
__LINE_OF__ (fun () -> check_layer_tree 0 (layer_tree 0));
__LINE_OF__ (fun () -> check_interval_tree (0., 10.) (interval_tree (0., 10.)));
__LINE_OF__ (fun () -> check_rational_tree (rational_tree ()));
__LINE_OF__ (fun () -> (top 0 a88_ex1) = Empty);
__LINE_OF__ (fun () -> (top 1 a88_ex1) = Node ('a', Empty, Empty));
__LINE_OF__ (fun () -> (top 3 a88_ex1) = (Node ('a', Node ('a', Node ('a', Empty, Empty), Node ('a', Empty, Empty)), Node ('a', Node ('a', Empty, Empty), Node ('a', Empty, Empty)))));
__LINE_OF__ (fun () -> (top 3 a88_ex2) = (Node ([], Node ([0], Node ([0;0], Empty, Empty), Node ([1;0], Empty, Empty)), Node ([1], Node ([0;1], Empty, Empty), Node ([1;1], Empty, Empty)))));
__LINE_OF__ (fun () -> (compare_ltrees 3 a88_ex1 (map (fun _ -> 'a') a88_ex2)));
__LINE_OF__ (fun () -> (compare_ltrees 3 a88_ex3 (map (fun x -> let l = List.length x in l * l) a88_ex2)));
__LINE_OF__ (fun () -> (compare_ltrees 3 a88_ex1 (find (fun x -> x = 'a') a88_ex1)));
__LINE_OF__ (fun () -> (compare_ltrees 3 a88_ex5 (find (fun x -> x >= 1000) a88_ex4)));
]
let () =
let rec input_lines ch =
(try Some (input_line ch) with _ -> None) (* catch stupid EOF exception *)
|> function Some line -> line :: input_lines ch | None -> []
in
let lines = input_lines (open_in __FILE__) in
let open List in
let open Printf in
let fail l =
let line = nth lines (l-1) in
let test = String.sub line 25 (String.length line - 27) in
printf "test \027[31;m%s\027[0;m (line %d) failed!\n" test l;
in
let test (l, t) =
let ok = try t () with e -> print_endline (Printexc.to_string e); false in
if not ok then fail l;
ok
in
let passed = filter (fun x -> x) (map test tests) in
printf "passed %d/%d tests\n" (length passed) (length tests)