restructure + lecutre 07
This commit is contained in:
96 files changed
+458
-4
No files matched your search
+114
@@ -0,0 +1,114 @@
|
||||
(** [fact n] calculates the factorial of [n]; non tail recursive *)
|
||||
let rec fact n =
|
||||
if n = 0. then 1.
|
||||
else n *. fact(n -. 1.);;
|
||||
|
||||
(**/**)
|
||||
let test_fact () =
|
||||
assert (fact 0. = 1.);
|
||||
assert (fact 3. = 6.);
|
||||
assert (fact 5. = 120.)
|
||||
(**/**)
|
||||
|
||||
(** [fact_tr n] calculates the factorial of [n]; tail recursive *)
|
||||
let fact_tr n =
|
||||
let rec fact_tr' acc i =
|
||||
if i = 0. then acc
|
||||
else fact_tr' (i *. acc) (i -. 1.)
|
||||
in
|
||||
fact_tr' 1. n;;
|
||||
|
||||
(**/**)
|
||||
let test_fact_tr () =
|
||||
assert (fact_tr 0. = 1.);
|
||||
assert (fact_tr 3. = 6.);
|
||||
assert (fact_tr 5. = 120.)
|
||||
(**/**)
|
||||
|
||||
(** [pow_tr a b] calculates [a] to the power of [b]; non tail recursive *)
|
||||
let rec pow a b =
|
||||
if b = 0. then 1.
|
||||
else a *. pow a (b -. 1.);;
|
||||
|
||||
(**/**)
|
||||
let test_pow () =
|
||||
assert (pow 0. 1. = 0.);
|
||||
assert (pow 0. 5. = 0.);
|
||||
assert (pow 1. 0. = 1.);
|
||||
assert (pow 5. 0. = 1.);
|
||||
assert (pow 1. 1. = 1.);
|
||||
assert (pow 5. 1. = 5.);
|
||||
assert (pow 2. 3. = 8.)
|
||||
(**/**)
|
||||
|
||||
(** [pow_tr a b] calculates [a] to the power of [b]; tail recursive *)
|
||||
let pow_tr a b =
|
||||
let rec pow_tr' acc i =
|
||||
if i = 0. then acc
|
||||
else pow_tr' (acc *. a) (i -. 1.)
|
||||
in
|
||||
pow_tr' 1. b;;
|
||||
|
||||
(**/**)
|
||||
let test_pow_tr () =
|
||||
assert (pow_tr 0. 1. = 0.);
|
||||
assert (pow_tr 0. 5. = 0.);
|
||||
assert (pow_tr 1. 0. = 1.);
|
||||
assert (pow_tr 5. 0. = 1.);
|
||||
assert (pow_tr 1. 1. = 1.);
|
||||
assert (pow_tr 5. 1. = 5.);
|
||||
assert (pow_tr 2. 3. = 8.)
|
||||
(**/**)
|
||||
|
||||
(** [expo_tr n x] calculates the approximation of e to the power of [x];
|
||||
* with a max iteration detail of [n]; non tail recursive
|
||||
* Require: [n] >= 1
|
||||
*)
|
||||
let rec expo n x =
|
||||
if n = 0 then 1.
|
||||
else pow x (float_of_int n) /. fact (float_of_int n) +.
|
||||
expo (n - 1) x;;
|
||||
|
||||
(**/**)
|
||||
let test_expo () =
|
||||
let tolerance = 1e-6 in
|
||||
let diff = abs_float (expo 20 1. -. exp 1.) in
|
||||
assert (diff < tolerance);
|
||||
let diff = abs_float (expo 20 2. -. exp 2.) in
|
||||
assert (diff < tolerance);
|
||||
let diff = abs_float (expo 20 3. -. exp 3.) in
|
||||
assert (diff < tolerance)
|
||||
(**/**)
|
||||
|
||||
(** [expo_tr n x] calculates the approximation of e to the power of [x];
|
||||
* with a max iteration detail of [n]; tail recursive
|
||||
* Require: [n] >= 1
|
||||
*)
|
||||
let expo_tr n x =
|
||||
let rec expo_tr' acc i =
|
||||
if i = 0 then acc
|
||||
else expo_tr' (acc +. pow_tr x (float_of_int i) /.
|
||||
fact_tr (float_of_int i)) (i - 1)
|
||||
in
|
||||
expo_tr' 1. n;;
|
||||
|
||||
(**/**)
|
||||
let test_expo_tr () =
|
||||
let tolerance = 1e-6 in
|
||||
let diff = abs_float (expo_tr 20 1. -. exp 1.) in
|
||||
assert (diff < tolerance);
|
||||
let diff = abs_float (expo_tr 20 2. -. exp 2.) in
|
||||
assert (diff < tolerance);
|
||||
let diff = abs_float (expo_tr 20 3. -. exp 3.) in
|
||||
assert (diff < tolerance)
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_fact();
|
||||
test_fact_tr();
|
||||
test_pow();
|
||||
test_pow_tr();
|
||||
test_expo();
|
||||
test_expo_tr()
|
||||
(**/**)
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
(** [reverse l] returns the reverse order of list [l]; non tail recursive *)
|
||||
let rec reverse l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x :: xs -> reverse xs @ [x];;
|
||||
|
||||
(**/**)
|
||||
let test_reverse () =
|
||||
assert (reverse [] = []);
|
||||
assert (reverse [1] = [1]);
|
||||
assert (reverse [1; 2] = [2; 1])
|
||||
(**/**)
|
||||
|
||||
(** [reverse_tr l] returns the reverse order of list [l]; tail recursive *)
|
||||
let reverse_tr l =
|
||||
let rec reverse_tr' acc l =
|
||||
match l with
|
||||
| [] -> acc
|
||||
| x :: xs -> reverse_tr' (x :: acc) xs
|
||||
in
|
||||
reverse_tr' [] l;;
|
||||
|
||||
(**/**)
|
||||
let test_reverse_tr () =
|
||||
assert (reverse_tr [] = []);
|
||||
assert (reverse_tr [1] = [1]);
|
||||
assert (reverse_tr [1; 2] = [2; 1])
|
||||
(**/**)
|
||||
|
||||
(** [zip l1 l2] combines elements from [l1] and [l2] into a
|
||||
* new list of tuples; non tail recursive
|
||||
*)
|
||||
let rec zip l1 l2 =
|
||||
match l1, l2 with
|
||||
| [], _ | _, [] -> [] (* if l1 or l2 is empty, return empty *)
|
||||
| x1 :: xs1, x2 :: xs2 ->
|
||||
(x1, x2) :: zip xs1 xs2;;
|
||||
|
||||
(**/**)
|
||||
let test_zip () =
|
||||
assert (zip [] [] = []);
|
||||
assert (zip [1] [] = []);
|
||||
assert (zip [] ['a'] = []);
|
||||
assert (zip [1; 2; 3] ['a'; 'b'] = [(1, 'a'); (2, 'b')]);
|
||||
assert (zip [1; 2; 3] ['a'; 'b'; 'c'] = [(1, 'a'); (2, 'b'); (3, 'c')])
|
||||
(**/**)
|
||||
|
||||
(** [zip_tr l1 l2] combines elements from [l1] and [l2] into a
|
||||
* new list of tuples; tail recursive
|
||||
*)
|
||||
let zip_tr l1 l2 =
|
||||
let rec zip_tr' acc l1 l2 =
|
||||
match l1, l2 with
|
||||
| [], _ | _, [] -> reverse_tr acc (* if l1 or l2 is empty, return empty *)
|
||||
| x1 :: xs1, x2 :: xs2 ->
|
||||
zip_tr' ((x1, x2) :: acc) xs1 xs2
|
||||
in
|
||||
zip_tr' [] l1 l2;;
|
||||
|
||||
(**/**)
|
||||
let test_zip_tr () =
|
||||
assert (zip_tr [] [] = []);
|
||||
assert (zip_tr [1] [] = []);
|
||||
assert (zip_tr [] ['a'] = []);
|
||||
assert (zip_tr [1; 2; 3] ['a'; 'b'] = [(1, 'a'); (2, 'b')]);
|
||||
assert (zip_tr [1; 2; 3] ['a'; 'b'; 'c'] = [(1, 'a'); (2, 'b'); (3, 'c')])
|
||||
(**/**)
|
||||
|
||||
(** [unzip l] takes in a list of tuples [l] where each tuple is
|
||||
* a pair, we seperate the pairs (x, y) into sepeate lists, ([x], [y])
|
||||
* and return a tuple of both lists; non tail recursive *)
|
||||
let rec unzip l =
|
||||
match l with
|
||||
| [] -> ([], [])
|
||||
| (x, y) :: xys ->
|
||||
let (l1, l2) = unzip xys in
|
||||
x :: l1, y :: l2;;
|
||||
|
||||
(**/**)
|
||||
let test_unzip () =
|
||||
assert (unzip [] = ([], []));
|
||||
assert (unzip [(1, 'a')] = ([1], ['a']));
|
||||
assert (unzip [(1, 'a'); (2, 'b')] = ([1; 2], ['a'; 'b']))
|
||||
(**/**)
|
||||
|
||||
(** [unzip_tr l] takes in a list of tuples [l] where each tuple is
|
||||
* a pair, we seperate the pairs (x, y) into sepeate lists, ([x], [y])
|
||||
* and return a tuple of both lists; tail recursive *)
|
||||
let unzip_tr l =
|
||||
let rec unzip_tr' (a1, a2) l =
|
||||
match l with
|
||||
| [] -> (a1, a2)
|
||||
| (x, y) :: xys ->
|
||||
unzip_tr' (x :: a1, y :: a2) xys
|
||||
in
|
||||
unzip_tr' ([], []) (reverse_tr l);;
|
||||
|
||||
(**/**)
|
||||
let test_unzip_tr () =
|
||||
assert (unzip_tr [] = ([], []));
|
||||
assert (unzip_tr [(1, 'a')] = ([1], ['a']));
|
||||
assert (unzip_tr [(1, 'a'); (2, 'b')] = ([1; 2], ['a'; 'b']))
|
||||
(**/**)
|
||||
|
||||
(** [dedup l] takes in a list [l] and collapses consecutive duplicated
|
||||
* elements into a single element; non tail recursive *)
|
||||
let rec dedup l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| [x] -> l
|
||||
| x :: y :: zs ->
|
||||
if x = y then dedup (x :: zs)
|
||||
else x :: dedup (y :: zs);;
|
||||
|
||||
(**/**)
|
||||
let test_dedup () =
|
||||
assert (dedup [] = []);
|
||||
assert (dedup [1] = [1]);
|
||||
assert (dedup [1; 2] = [1; 2]);
|
||||
assert (dedup [1; 1; 2; 2; 2; 1; 3; 3; 2] = [1; 2; 1; 3; 2]);
|
||||
assert (dedup [1; 1; 2; 2; 2; 1; 3; 3; 2; 4] = [1; 2; 1; 3; 2; 4])
|
||||
(**/**)
|
||||
|
||||
(** [dedup l] takes in a list [l] and collapses consecutive duplicated
|
||||
* elements into a single element; tail recursive *)
|
||||
let dedup_tr l =
|
||||
let rec dedup' acc l =
|
||||
match l with
|
||||
| [] -> acc
|
||||
| [x] -> reverse_tr (x :: acc)
|
||||
| x :: y :: zs ->
|
||||
if x = y then dedup' acc (x :: zs)
|
||||
else dedup' (x :: acc) (y :: zs)
|
||||
in
|
||||
dedup' [] l;;
|
||||
|
||||
(**/**)
|
||||
let test_dedup_tr () =
|
||||
assert (dedup_tr [] = []);
|
||||
assert (dedup_tr [1] = [1]);
|
||||
assert (dedup_tr [1; 2] = [1; 2]);
|
||||
assert (dedup_tr [1; 1; 2; 2; 2; 1; 3; 3; 2] = [1; 2; 1; 3; 2])
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_reverse();
|
||||
test_reverse_tr();
|
||||
test_zip();
|
||||
test_zip_tr();
|
||||
test_unzip();
|
||||
test_unzip_tr();
|
||||
test_dedup();
|
||||
test_dedup_tr();
|
||||
(**/**)
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
(** [fold_right f l acc] applies function [f] to each element of list [l]
|
||||
* from right to left, adding to the accumulator [acc].
|
||||
* The function [f] takes the current element and accumulator
|
||||
* and produces a new accumulator.
|
||||
*)
|
||||
let rec fold_right f l acc =
|
||||
match l with
|
||||
| [] -> acc
|
||||
| x :: xs -> f x (fold_right f xs acc);;
|
||||
|
||||
(**/**)
|
||||
let test_fold_right () =
|
||||
assert (fold_right (+) [] 0 = 0);
|
||||
assert (fold_right (+) [2] 0 = 2);
|
||||
assert (fold_right (+) [1; 2; 3; 4] 0 = 10)
|
||||
(**/**)
|
||||
|
||||
(** [map f l] for each element in list [l] apply func [f]
|
||||
* return list of [l] with func [f] applied to elems *)
|
||||
let map f l = fold_right (fun x acc -> f x :: acc) l [];;
|
||||
|
||||
(**/**)
|
||||
let test_map () =
|
||||
assert (map (fun x -> x * x) [] = []);
|
||||
assert (map (fun x -> x * x) [5] = [25]);
|
||||
assert (map (fun x -> x * x) [1; 2; 3] = [1; 4; 9]);
|
||||
assert (map (fun x -> x + x) [1; 2; 3] = [2; 4; 6]);
|
||||
assert (map (fun x -> 2. ** x) [0.; 1.; 2.; 3.; 4.; 5.] = [1.; 2.; 4.; 8.; 16.; 32.])
|
||||
(**/**)
|
||||
|
||||
(** [dedup l] takes in a list [l] and collapses consecutive duplicated
|
||||
* elements into a single element *)
|
||||
let dedup l = fold_right (fun x acc ->
|
||||
match acc with
|
||||
| y :: ys when y = x -> acc
|
||||
| _ -> x :: acc
|
||||
) l [];;
|
||||
|
||||
(**/**)
|
||||
let test_dedup () =
|
||||
assert (dedup [] = []);
|
||||
assert (dedup [1] = [1]);
|
||||
assert (dedup [1; 2] = [1; 2]);
|
||||
assert (dedup [1; 1; 2; 2; 2; 1; 3; 3; 2] = [1; 2; 1; 3; 2]);
|
||||
assert (dedup [1; 1; 2; 2; 2; 1; 3; 3; 2; 4] = [1; 2; 1; 3; 2; 4])
|
||||
(**/**)
|
||||
|
||||
(** [reverse_tr l] returns the reverse order of list [l]; tail recursive *)
|
||||
let reverse l =
|
||||
let rec reverse' acc l =
|
||||
match l with
|
||||
| [] -> acc
|
||||
| x :: xs -> reverse' (x :: acc) xs
|
||||
in
|
||||
reverse' [] l;;
|
||||
|
||||
(**/**)
|
||||
let test_reverse () =
|
||||
assert (reverse [] = []);
|
||||
assert (reverse [1] = [1]);
|
||||
assert (reverse [1; 2] = [2; 1]);
|
||||
assert (reverse [1; 2; 3] = [3; 2; 1])
|
||||
(**/**)
|
||||
|
||||
(** [filteri f l] for each element in list [l] keep
|
||||
* element if it passes predicate func [f] where
|
||||
* the predicate [f] takes an index i and elem x *)
|
||||
let filteri f l =
|
||||
let rec filteri' i l acc =
|
||||
match l with
|
||||
| [] -> reverse acc
|
||||
| x :: xs when f i x -> filteri' (i + 1) xs (x :: acc)
|
||||
| _ :: xs -> filteri' (i + 1) xs acc
|
||||
in
|
||||
filteri' 0 l [];;
|
||||
|
||||
(**/**)
|
||||
let test_filteri () =
|
||||
assert (filteri (fun i x -> i > 3 && x mod 2 = 0) [1; 2; 3; 4; 5; 6] = [6]);
|
||||
assert (filteri (fun i x -> i < 3 && x mod 2 != 0) [1; 2; 3; 4; 5; 6] = [1; 3]);
|
||||
assert (filteri (fun i x -> i != 1 && x >= 0) [-1; 0; 1; 2] = [1; 2])
|
||||
(**/**)
|
||||
|
||||
(** [filteri f l] for each element in list [l] keep
|
||||
* element if it passes predicate func [f] where
|
||||
* the predicate [f] takes an element x *)
|
||||
let filter f l = filteri (fun _ x -> f x) l;;
|
||||
|
||||
(**/**)
|
||||
let test_filter () =
|
||||
assert (filter (fun x -> x mod 2 = 0) [1; 2; 3; 4; 5; 6] = [2; 4; 6]);
|
||||
assert (filter (fun x -> x mod 2 != 0) [1; 2; 3; 4; 5; 6] = [1; 3; 5]);
|
||||
assert (filter (fun x -> x > 0) [-1; 0; 1; 2] = [1; 2])
|
||||
(**/**)
|
||||
|
||||
(** [every n l] returns a list of elements containing
|
||||
every [n]th elemnt from list [l]
|
||||
Required: [n] > 0 *)
|
||||
let every n l = filteri (fun i _ -> (i + 1) mod n = 0) l;;
|
||||
|
||||
(**/**)
|
||||
let test_every () =
|
||||
assert (every 1 [] = []);
|
||||
assert (every 2 [1] = []);
|
||||
assert (every 3 [1;2;3;4;5;6;7;8;9;10] = [3;6;9]);
|
||||
assert (every 2 [1;2;3;4;5;6;7;8] = [2;4;6;8])
|
||||
(**/**)
|
||||
|
||||
(** [fold_while f acc l] folds over [l] from left to right using [f]
|
||||
and accumulator [acc], stopping early if [f] returns [None]. *)
|
||||
let rec fold_while f acc l =
|
||||
match l with
|
||||
| [] -> acc
|
||||
| x :: xs ->
|
||||
match f acc x with
|
||||
| None -> acc
|
||||
| Some acc' -> fold_while f acc' xs;;
|
||||
|
||||
(**/**)
|
||||
let test_fold_while () =
|
||||
let p = (fun acc x ->
|
||||
if acc + x > 10 then None
|
||||
else Some (acc + x)
|
||||
) in
|
||||
|
||||
assert (fold_while p 0 [] = 0);
|
||||
assert (fold_while p 0 [1;2;3;4] = 10);
|
||||
assert (fold_while p 0 [5;5;5] = 10);
|
||||
assert (fold_while p 0 [2;2;2;2;2;2] = 10);
|
||||
assert (fold_while p 0 [20;1;2;3] = 0)
|
||||
(**/**)
|
||||
|
||||
(** [fold_left f acc l] applies function [f] to each element of list [l]
|
||||
* from left to right, adding to the accumulator [acc].
|
||||
* The function [f] takes the current element and accumulator
|
||||
* and produces a new accumulator.
|
||||
*)
|
||||
let fold_left f acc l = fold_while (fun acc x -> Some (f acc x)) acc l;;
|
||||
|
||||
(**/**)
|
||||
let test_fold_left () =
|
||||
assert (fold_left (+) 0 [] = 0);
|
||||
assert (fold_left (+) 0 [1;2;3;4;5] = 15);
|
||||
assert (fold_left ( * ) 1 [1;2;3;4] = 24);
|
||||
assert (fold_left (-) 0 [1;2;3] = -6);
|
||||
assert (fold_left (fun acc x -> acc ^ x) "" ["a"; "b"; "c"] = "abc")
|
||||
(**/**)
|
||||
|
||||
(** [sum_while_less_than n l] takes a list of integers [l] and
|
||||
and maximum value [n]. Where it sums elements of the list [l]
|
||||
until the sum reaches a maximum [n] and returns a pair of the
|
||||
count and the sum.
|
||||
*)
|
||||
let sum_while_less_than n l =
|
||||
let sum (c, acc) x =
|
||||
if acc + x >= n then None
|
||||
else Some (c + 1, acc + x)
|
||||
in
|
||||
fold_while sum (0, 0) l;;
|
||||
|
||||
(**/**)
|
||||
let test_sum_while_less_than () =
|
||||
assert (sum_while_less_than 0 [6; 5; 5; 3; 4] = (0, 0));
|
||||
assert (sum_while_less_than 20 [6; 5; 5; 3; 4] = (4, 19));
|
||||
assert (sum_while_less_than 6 [6; 5; 5; 3; 4] = (0, 0));
|
||||
assert (sum_while_less_than 6 [] = (0, 0))
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests() =
|
||||
test_fold_left();
|
||||
test_fold_right();
|
||||
test_map();
|
||||
test_dedup();
|
||||
test_reverse();
|
||||
test_filteri();
|
||||
test_filter();
|
||||
test_every();
|
||||
test_fold_while();
|
||||
test_sum_while_less_than()
|
||||
(**/**)
|
||||
@@ -0,0 +1,215 @@
|
||||
(* default comparator for testing *)
|
||||
let scmp = String.compare;;
|
||||
|
||||
(** [kvtree] is a key value tree where each node has a key, value, left and right *)
|
||||
type ('k, 'v) kvtree = Leaf | Node of 'k * 'v * ('k, 'v) kvtree * ('k, 'v) kvtree;;
|
||||
|
||||
(* example of an empty kvtree *)
|
||||
let kvtree_empty = Leaf;;
|
||||
|
||||
(** [kvtree_insert ~cmp k v t] takes a comparator [~cmp], key [k], value [v],
|
||||
and a kvtree [t] to insert the key and value [k, v] into the tree [t] in
|
||||
the order specefied by the comparator [~cmp] to compare keys *)
|
||||
let rec kvtree_insert ~cmp k v t =
|
||||
match t with
|
||||
| Leaf -> Node (k, v, Leaf, Leaf)
|
||||
| Node (k', v', l, r) when cmp k k' < 0 ->
|
||||
Node (k', v', kvtree_insert ~cmp k v l, r)
|
||||
| Node (k', v', l, r) when cmp k k' > 0 ->
|
||||
Node (k', v', l, kvtree_insert ~cmp k v r)
|
||||
| Node (k', _, l, r) when cmp k k' = 0 ->
|
||||
Node (k, v, l, r)
|
||||
| _ -> t;;
|
||||
|
||||
(**/**)2
|
||||
let test_kvtree_insert () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_insert ~cmp:scmp "Bread" 20 Leaf = a);
|
||||
assert (kvtree_insert ~cmp:scmp "Mitch" 22 a = b);
|
||||
assert (kvtree_insert ~cmp:scmp "Luka" 19 b = c)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_of_list ~cmp l] takes a list of pairs [l] and creates a
|
||||
kvtree in the order specefied by the comparator [~cmp] to compare
|
||||
keys *)
|
||||
let kvtree_of_list ~cmp l =
|
||||
List.fold_left (fun acc (k, v) -> kvtree_insert ~cmp k v acc) Leaf l;;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_of_list () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
assert (kvtree_of_list ~cmp:scmp [] = Leaf);
|
||||
assert (kvtree_of_list ~cmp:scmp [("Bread", 20)] = a);
|
||||
assert (kvtree_of_list ~cmp:scmp [("Bread", 20); ("Mitch", 22)] = b)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_is_empty t] takes a kvtree [t] and checks if it is empty or not *)
|
||||
let kvtree_is_empty t = t = Leaf;;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_is_empty () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
assert (kvtree_is_empty Leaf = true);
|
||||
assert (kvtree_is_empty a = false);
|
||||
assert (kvtree_is_empty b = false)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_size t] takes a kvtree [t] and returns the size of the tree
|
||||
i.e. number of nodes *)
|
||||
let rec kvtree_size t =
|
||||
match t with
|
||||
| Leaf -> 0
|
||||
| Node (_, _, l, r) ->
|
||||
1 + kvtree_size l + kvtree_size r;;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_size () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_size Leaf = 0);
|
||||
assert (kvtree_size a = 1);
|
||||
assert (kvtree_size b = 2);
|
||||
assert (kvtree_size c = 3)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_height t] takes a kvtree [t] and returns the height of
|
||||
the tree (how deep the nodes go down in the tree) *)
|
||||
let rec kvtree_height t =
|
||||
match t with
|
||||
| Leaf -> 0
|
||||
| Node (_, _, l, r) ->
|
||||
1 + max (kvtree_height l) (kvtree_height r);;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_height () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_height Leaf = 0);
|
||||
assert (kvtree_height a = 1);
|
||||
assert (kvtree_height b = 2);
|
||||
assert (kvtree_height c = 3)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_mem ~cmp k t] checks if a given key [k] is in a given kvtree
|
||||
[t] in the order specified by the comparator [~cmp] *)
|
||||
let rec kvtree_mem ~cmp k t =
|
||||
match t with
|
||||
| Leaf -> false
|
||||
| Node (k', _, l, _) when cmp k k' < 0 ->
|
||||
kvtree_mem ~cmp k l
|
||||
| Node (k', _, _, r) when cmp k k' > 0 ->
|
||||
kvtree_mem ~cmp k r
|
||||
| _ -> true;;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_mem () =
|
||||
let a = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_mem ~cmp:scmp "Bread" Leaf = false);
|
||||
assert (kvtree_mem ~cmp:scmp "Bread" a = true);
|
||||
assert (kvtree_mem ~cmp:scmp "Mitch" a = true);
|
||||
assert (kvtree_mem ~cmp:scmp "Ryan" a = false)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_largest t] finds the largest key in a given kvtree [t]
|
||||
and retursn the key value pair [k, v] *)
|
||||
let rec kvtree_largest t =
|
||||
match t with
|
||||
| Leaf -> failwith "kvtree_largest: empty tree"
|
||||
| Node (k, v, _, Leaf) -> (k, v)
|
||||
| Node (_, _, _, r) -> kvtree_largest r;;
|
||||
|
||||
(**/**)
|
||||
(* largest by key not by value *)
|
||||
let test_kvtree_largest () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_largest a = ("Bread", 20));
|
||||
assert (kvtree_largest b = ("Mitch", 22));
|
||||
assert (kvtree_largest c = ("Mitch", 22))
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_smallest t] finds the smallest key in a given kvtree [t]
|
||||
and retursn the key value pair [k, v] *)
|
||||
let rec kvtree_smallest t =
|
||||
match t with
|
||||
| Leaf -> failwith "kvtree_smallest: empty tree"
|
||||
| Node (k, v, Leaf, _) -> (k, v)
|
||||
| Node (_, _, l, _) -> kvtree_smallest l;;
|
||||
|
||||
(**/**)
|
||||
(* smallest by key not by value *)
|
||||
let test_kvtree_smallest () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_smallest a = ("Bread", 20));
|
||||
assert (kvtree_smallest b = ("Bread", 20));
|
||||
assert (kvtree_smallest c = ("Bread", 20))
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_delete ~cmp k t] takes a key [k] and deletes it from a given
|
||||
kvtree [t] in the order specefied by the comparator [~cmp] *)
|
||||
let rec kvtree_delete ~cmp k t =
|
||||
match t with
|
||||
| Leaf -> Leaf
|
||||
| Node (k', v, l, r) when cmp k k' < 0 ->
|
||||
Node (k', v, kvtree_delete ~cmp k l, r)
|
||||
| Node (k', v, l, r) when cmp k k' > 0 ->
|
||||
Node (k', v, l, kvtree_delete ~cmp k r)
|
||||
| Node (_, _, l, Leaf) -> l
|
||||
| Node (_, _, Leaf, r) -> r
|
||||
| Node (_, _, l, r) ->
|
||||
let (ks, vs) = kvtree_largest l in
|
||||
Node (ks, vs, kvtree_delete ~cmp ks l, r);;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_delete () =
|
||||
let a = Node ("Bread", 20, Leaf, Leaf) in
|
||||
let b = Node ("Bread", 20, Leaf, Node("Mitch", 22, Leaf, Leaf)) in
|
||||
let c = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
let d = Node ("Bread", 20, Leaf, Node("Luka", 19, Leaf, Leaf)) in
|
||||
assert (kvtree_delete ~cmp:scmp "Bread" a = Leaf);
|
||||
assert (kvtree_delete ~cmp:scmp "Mitch" c = d);
|
||||
assert (kvtree_delete ~cmp:scmp "Luka" c = b)
|
||||
(**/**)
|
||||
|
||||
(** [kvtree_find_opt ~cmp k t] takes a key [k] and a kvtree [t] and returns
|
||||
and Optional value found from the given key [k]. Searching through the
|
||||
tree in the order specefied by the comparator [~cmp] *)
|
||||
let rec kvtree_find_opt ~cmp k t =
|
||||
match t with
|
||||
| Leaf -> None
|
||||
| Node (k', _, l, _) when cmp k k' < 0 ->
|
||||
kvtree_find_opt ~cmp k l
|
||||
| Node (k', _, _, r) when cmp k k' > 0 ->
|
||||
kvtree_find_opt ~cmp k r
|
||||
| Node (_, v, _, _) -> Some v;;
|
||||
|
||||
(**/**)
|
||||
let test_kvtree_find_opt () =
|
||||
let a = Node ("Bread", 20, Leaf, Node("Mitch", 22, Node("Luka", 19, Leaf, Leaf), Leaf)) in
|
||||
assert (kvtree_find_opt ~cmp:scmp "Luka" Leaf = None);
|
||||
assert (kvtree_find_opt ~cmp:scmp "Ryan" a = None);
|
||||
assert (kvtree_find_opt ~cmp:scmp "Bread" a = Some 20);
|
||||
assert (kvtree_find_opt ~cmp:scmp "Mitch" a = Some 22)
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_kvtree_insert();
|
||||
test_kvtree_of_list();
|
||||
test_kvtree_is_empty();
|
||||
test_kvtree_size();
|
||||
test_kvtree_height();
|
||||
test_kvtree_mem();
|
||||
test_kvtree_largest();
|
||||
test_kvtree_smallest();
|
||||
test_kvtree_delete();
|
||||
test_kvtree_find_opt()
|
||||
@@ -0,0 +1,36 @@
|
||||
(** [digits n] takes a positive integer [n] and returns
|
||||
a list of integers of each digit in the number [n] *)
|
||||
let digits n =
|
||||
let rec digits' n acc =
|
||||
if n = 0 then acc
|
||||
else digits' (n / 10) (n mod 10 :: acc)
|
||||
in
|
||||
digits' n [];;
|
||||
|
||||
(**/**)
|
||||
let test_digits () =
|
||||
assert (digits 0 = []);
|
||||
assert (digits 123 = [1;2;3]);
|
||||
assert (digits 123040 = [1;2;3;0;4;0])
|
||||
(**/**)
|
||||
|
||||
(** [int_of_digits d] takes a list of positive integers [d]
|
||||
and returns a single number where each digit is from the
|
||||
list [d]
|
||||
*)
|
||||
let int_of_digits d =
|
||||
List.fold_left (fun x acc -> x * 10 + acc) 0 d;;
|
||||
|
||||
(**/**)
|
||||
let test_int_of_digits () =
|
||||
assert (int_of_digits [] = 0);
|
||||
assert (int_of_digits [0] = 0);
|
||||
assert (int_of_digits [0;0;1;2;3] = 123);
|
||||
assert (int_of_digits [2;0;0;5] = 2005)
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_digits();
|
||||
test_int_of_digits()
|
||||
(**/**)
|
||||
@@ -0,0 +1,5 @@
|
||||
"Rule: ocaml dependencies ml (%=records )": "\168\187\158\232\128I\157\015\216j\244\004\243\234\011\217"
|
||||
"Rule: ocaml: ml & cmi -> cmx & o (%=records )": "5\144\205\021B\003\025\204\145\159\255\166t\136\140^"
|
||||
"Resource: /home/flami/Projects/comp3958/lab04/records.ml": "\133\242qUUy2\188\b\134=\163c9\2142"
|
||||
"Rule: ocaml: ml -> cmo & cmi (%=records )": "\026zi!\193g\255\238<\162\135s\021\142\001\012"
|
||||
"Rule: ocaml: cmx* & o* -> native (%=records )": "C\176\141F\181\127\251\240\211V\156\t\167\208\129\177"
|
||||
@@ -0,0 +1,12 @@
|
||||
### Starting build.
|
||||
# Target: /home/flami/.opam/default/bin/ocamlc.opt -config, tags: { }
|
||||
/home/flami/.opam/default/bin/ocamlc.opt -config
|
||||
# Target: records.ml.depends, tags: { extension:ml, file:records.ml, ocaml, ocamldep, quiet }
|
||||
/home/flami/.opam/default/bin/ocamldep.opt -modules records.ml > records.ml.depends
|
||||
# Target: records.cmo, tags: { byte, compile, extension:cmo, extension:ml, file:records.cmo, file:records.ml, implem, ocaml, quiet }
|
||||
/home/flami/.opam/default/bin/ocamlc.opt -c -o records.cmo records.ml
|
||||
# Target: records.cmx, tags: { compile, extension:cmx, extension:ml, file:records.cmx, file:records.ml, implem, native, ocaml, quiet }
|
||||
/home/flami/.opam/default/bin/ocamlopt.opt -c -o records.cmx records.ml
|
||||
# Target: records.native, tags: { dont_link_with, extension:native, file:records.native, link, native, ocaml, program, quiet }
|
||||
/home/flami/.opam/default/bin/ocamlopt.opt records.cmx -o records.native
|
||||
# Compilation successful.
|
||||
Binary file not shown.
@@ -0,0 +1,143 @@
|
||||
(** [record] of a person with a first name, last name, and score *)
|
||||
type record = {firstname: string; lastname: string; score: int};;
|
||||
|
||||
(** [print_records r] takes a list of records [r] and prints
|
||||
* each record neatly to the console *)
|
||||
let rec print_records r =
|
||||
match r with
|
||||
| [] -> ()
|
||||
| x :: xs -> Printf.printf "%3d %s %s\n" x.score x.lastname x.firstname; print_records xs;;
|
||||
|
||||
(** [compare_records r1 r2] compares records [r1] and [r2] based
|
||||
* on score, then by lastname, then by firstname.
|
||||
*)
|
||||
let compare_records r1 r2 =
|
||||
compare
|
||||
(r2.score, r2.lastname, r2.firstname)
|
||||
(r1.score, r1.lastname, r1.firstname);;
|
||||
|
||||
(** [records_insert x l] inserts a record element [x] into
|
||||
* list of records [l]
|
||||
* Requires: [l] is in ascending order. *)
|
||||
let rec records_insert x l =
|
||||
match l with
|
||||
| y :: ys when compare_records x y > 0 -> y :: records_insert x ys
|
||||
| _ -> x :: l;;
|
||||
|
||||
(**/**)
|
||||
let test_records_insert () =
|
||||
assert (records_insert
|
||||
{firstname = "a"; lastname = "b"; score = 1} [] =
|
||||
[{firstname = "a"; lastname = "b"; score = 1}]
|
||||
);
|
||||
assert (records_insert
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
[{firstname = "c"; lastname = "d"; score = 2}] =
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
]);
|
||||
assert (records_insert
|
||||
{firstname = "e"; lastname = "f"; score = 2}
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
] =
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
]);;
|
||||
(**/**)
|
||||
|
||||
(** [records_insertion_sort l] sorts list of records [l] in ascending order *)
|
||||
let rec sort_records l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x :: xs -> records_insert x (sort_records xs);;
|
||||
|
||||
(**/**)
|
||||
let test_sort_records () =
|
||||
assert (sort_records [] = []);
|
||||
assert (sort_records
|
||||
[{firstname = "a"; lastname = "b"; score = 1}] =
|
||||
[{firstname = "a"; lastname = "b"; score = 1}]);
|
||||
|
||||
assert (sort_records [
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "a"; lastname = "b"; score = 1};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
] = [
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1};
|
||||
]);;
|
||||
(**/**)
|
||||
|
||||
(** [parse l] takes in a line [l] and parses the line to extract
|
||||
* firstname, lastname, and score, returning Some record if successful
|
||||
* or None if the input line [l] contains bad data *)
|
||||
let rec parse l =
|
||||
try
|
||||
Scanf.sscanf l " %s %s %s" (fun f l s ->
|
||||
match int_of_string_opt s with
|
||||
| Some v when v >= 0 && v <= 100 -> Some {firstname = f; lastname = l; score = v}
|
||||
| _ -> None
|
||||
)
|
||||
with
|
||||
| Scanf.Scan_failure _ -> None;;
|
||||
|
||||
(**/**)
|
||||
let test_parse () =
|
||||
assert (parse "" = None);
|
||||
assert (parse "Bart simpson 5abc" = None);
|
||||
assert (parse "Lisa simpson 130" = None);
|
||||
assert (parse "Homer Simpson -5" = None);
|
||||
assert (parse "Homer Simpson 5" =
|
||||
Some {firstname = "Homer"; lastname = "Simpson"; score = 5});
|
||||
assert (parse "Homer Simpson 5 blah blah blah" =
|
||||
Some {firstname = "Homer"; lastname = "Simpson"; score = 5});;
|
||||
(**/**)
|
||||
|
||||
(** [read_file acc ic] takes in an accumulator [acc] and an input channel [ic]
|
||||
* and oterates over it input channel [ic] to parse each line and store the
|
||||
* parsed result into the accumulator [acc] *)
|
||||
let rec read_file acc ic =
|
||||
try
|
||||
match parse @@ input_line ic with
|
||||
| None -> read_file acc ic
|
||||
| Some v -> read_file (v :: acc) ic
|
||||
with
|
||||
| End_of_file -> close_in ic; acc;;
|
||||
|
||||
(**/**)
|
||||
let test_read_file () =
|
||||
assert (read_file [] @@ open_in "data.txt" = [
|
||||
{firstname = "gary"; lastname = "chalmers"; score = 5};
|
||||
{firstname = "waylon"; lastname = "smithers"; score = 100};
|
||||
{firstname = "homer"; lastname = "simpson"; score = 25};
|
||||
]);
|
||||
assert (read_file [] @@ open_in "data1.txt" = [
|
||||
{firstname = "gary"; lastname = "chalmers"; score = 5};
|
||||
{firstname = "waylon"; lastname = "smithers"; score = 100};
|
||||
{firstname = "ned"; lastname = "flanders"; score = 12};
|
||||
{firstname = "homer"; lastname = "simpson"; score = 25};
|
||||
]);
|
||||
assert (read_file [] @@ open_in "data2.txt" = []);;
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_parse();
|
||||
test_read_file();
|
||||
test_records_insert();
|
||||
test_sort_records();;
|
||||
(**/**)
|
||||
|
||||
(** main program entry from cli *)
|
||||
let () =
|
||||
if Array.length Sys.argv = 1 then
|
||||
Printf.printf "%s: expects 1 file input.\nUsage: \"%s <filename>\"\n" Sys.argv.(0) Sys.argv.(0)
|
||||
else
|
||||
let ic = open_in Sys.argv.(1) in
|
||||
print_records @@ sort_records @@ read_file [] ic;;
|
||||
@@ -0,0 +1 @@
|
||||
records.ml: Array Printf Scanf Sys
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
homer simpson 25 # bad at nuclear engineering
|
||||
ned flanders 12abc !! invalid
|
||||
waylon smithers 100 ! high score
|
||||
gary chalmers 5
|
||||
monty burns
|
||||
@@ -0,0 +1,5 @@
|
||||
homer simpson 25 # bad at nuclear engineering
|
||||
ned flanders 12 !! valid
|
||||
waylon smithers 100 ! high score
|
||||
gary chalmers 5
|
||||
monty burns
|
||||
@@ -0,0 +1 @@
|
||||
monty burns
|
||||
@@ -0,0 +1,160 @@
|
||||
(** [record] of a person with a first name, last name, and score *)
|
||||
type record = {firstname: string; lastname: string; score: int};;
|
||||
|
||||
(** [print_records r] takes a list of records [r] and prints
|
||||
* each record neatly to the console *)
|
||||
let rec print_records r =
|
||||
match r with
|
||||
| [] -> ()
|
||||
| x :: xs -> Printf.printf "%3d %s %s\n" x.score x.lastname x.firstname; print_records xs;;
|
||||
|
||||
(** [compare_records r1 r2] compares records [r1] and [r2] based
|
||||
* on score, then by lastname, then by firstname.
|
||||
*)
|
||||
let compare_records r1 r2 =
|
||||
compare
|
||||
(r2.score, r2.lastname, r2.firstname)
|
||||
(r1.score, r1.lastname, r1.firstname);;
|
||||
|
||||
(**/**)
|
||||
let test_compare_records () =
|
||||
assert (compare_records
|
||||
{firstname = "homer"; lastname = "simpson"; score = 10}
|
||||
{firstname = "marge"; lastname = "simpson"; score = 25}
|
||||
> 0);
|
||||
assert (compare_records
|
||||
{firstname = "bart"; lastname = "simpson"; score = 25}
|
||||
{firstname = "marge"; lastname = "simpson"; score = 25}
|
||||
> 0);
|
||||
assert (compare_records
|
||||
{firstname = "marge"; lastname = "simpson"; score = 25}
|
||||
{firstname = "bart"; lastname = "simpson"; score = 25}
|
||||
< 0);;
|
||||
(**/**)
|
||||
|
||||
(** [records_insert x l] inserts a record element [x] into
|
||||
* list of records [l]
|
||||
* Requires: [l] is in ascending order. *)
|
||||
let rec records_insert x l =
|
||||
match l with
|
||||
| y :: ys when compare_records x y > 0 -> y :: records_insert x ys
|
||||
| _ -> x :: l;;
|
||||
|
||||
(**/**)
|
||||
let test_records_insert () =
|
||||
assert (records_insert
|
||||
{firstname = "a"; lastname = "b"; score = 1} [] =
|
||||
[{firstname = "a"; lastname = "b"; score = 1}]
|
||||
);
|
||||
assert (records_insert
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
[{firstname = "c"; lastname = "d"; score = 2}] =
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
]);
|
||||
assert (records_insert
|
||||
{firstname = "e"; lastname = "f"; score = 2}
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
] =
|
||||
[
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1}
|
||||
]);;
|
||||
(**/**)
|
||||
|
||||
(** [records_insertion_sort l] sorts list of records [l] in ascending order *)
|
||||
let rec sort_records l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x :: xs -> records_insert x (sort_records xs);;
|
||||
|
||||
(**/**)
|
||||
let test_sort_records () =
|
||||
assert (sort_records [] = []);
|
||||
assert (sort_records
|
||||
[{firstname = "a"; lastname = "b"; score = 1}] =
|
||||
[{firstname = "a"; lastname = "b"; score = 1}]);
|
||||
|
||||
assert (sort_records [
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "a"; lastname = "b"; score = 1};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
] = [
|
||||
{firstname = "c"; lastname = "d"; score = 3};
|
||||
{firstname = "e"; lastname = "f"; score = 2};
|
||||
{firstname = "a"; lastname = "b"; score = 1};
|
||||
]);;
|
||||
(**/**)
|
||||
|
||||
(** [parse l] takes in a line [l] and parses the line to extract
|
||||
* firstname, lastname, and score, returning Some record if successful
|
||||
* or None if the input line [l] contains bad data *)
|
||||
let rec parse l =
|
||||
try
|
||||
Scanf.sscanf l " %s %s %s" (fun f l s ->
|
||||
match int_of_string_opt s with
|
||||
| Some v when v >= 0 && v <= 100 -> Some {firstname = f; lastname = l; score = v}
|
||||
| _ -> None
|
||||
)
|
||||
with
|
||||
| Scanf.Scan_failure _ -> None;;
|
||||
|
||||
(**/**)
|
||||
let test_parse () =
|
||||
assert (parse "" = None);
|
||||
assert (parse "Bart simpson 5abc" = None);
|
||||
assert (parse "Lisa simpson 130" = None);
|
||||
assert (parse "Homer Simpson -5" = None);
|
||||
assert (parse "Homer Simpson 5" =
|
||||
Some {firstname = "Homer"; lastname = "Simpson"; score = 5});
|
||||
assert (parse "Homer Simpson 5 blah blah blah" =
|
||||
Some {firstname = "Homer"; lastname = "Simpson"; score = 5});;
|
||||
(**/**)
|
||||
|
||||
(** [read_file acc ic] takes in an accumulator [acc] and an input channel [ic]
|
||||
* and oterates over it input channel [ic] to parse each line and store the
|
||||
* parsed result into the accumulator [acc] *)
|
||||
let rec read_file acc ic =
|
||||
try
|
||||
match parse @@ input_line ic with
|
||||
| None -> read_file acc ic
|
||||
| Some v -> read_file (v :: acc) ic
|
||||
with
|
||||
| End_of_file -> close_in ic; acc;;
|
||||
|
||||
(**/**)
|
||||
let test_read_file () =
|
||||
assert (read_file [] @@ open_in "data.txt" = [
|
||||
{firstname = "gary"; lastname = "chalmers"; score = 5};
|
||||
{firstname = "waylon"; lastname = "smithers"; score = 100};
|
||||
{firstname = "homer"; lastname = "simpson"; score = 25};
|
||||
]);
|
||||
assert (read_file [] @@ open_in "data1.txt" = [
|
||||
{firstname = "gary"; lastname = "chalmers"; score = 5};
|
||||
{firstname = "waylon"; lastname = "smithers"; score = 100};
|
||||
{firstname = "ned"; lastname = "flanders"; score = 12};
|
||||
{firstname = "homer"; lastname = "simpson"; score = 25};
|
||||
]);
|
||||
assert (read_file [] @@ open_in "data2.txt" = []);;
|
||||
(**/**)
|
||||
|
||||
(**/**)
|
||||
let run_all_tests () =
|
||||
test_parse();
|
||||
test_read_file();
|
||||
test_compare_records();
|
||||
test_records_insert();
|
||||
test_sort_records();;
|
||||
(**/**)
|
||||
|
||||
(** main program entry from cli *)
|
||||
let () =
|
||||
if Array.length Sys.argv = 1 then
|
||||
Printf.printf "%s: expects 1 file input.\nUsage: \"%s <filename>\"\n" Sys.argv.(0) Sys.argv.(0)
|
||||
else
|
||||
let ic = open_in Sys.argv.(1) in
|
||||
print_records @@ sort_records @@ read_file [] ic;;
|
||||
@@ -0,0 +1,139 @@
|
||||
module type OrderedType = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
module type S = sig
|
||||
type k
|
||||
type ('k, 'v) t
|
||||
exception Not_found
|
||||
|
||||
val empty : (k, 'v) t
|
||||
val is_empty : (k, 'v) t -> bool
|
||||
val insert : k -> 'v -> (k, 'v) t -> (k, 'v) t
|
||||
val find_opt : k -> (k, 'v) t -> 'v option
|
||||
val delete : k -> (k, 'v) t -> (k, 'v) t
|
||||
val of_list : (k * 'v) list -> (k, 'v) t
|
||||
val size : (k, 'v) t -> int
|
||||
val find : k -> (k, 'v) t -> 'v
|
||||
val to_list : (k, 'v) t -> (k * 'v) list
|
||||
val to_string : ((k * 'v) -> string) -> (k, 'v) t -> string
|
||||
end
|
||||
|
||||
module Make(Ord: OrderedType) = struct
|
||||
(** [k] is the key of a key-value pair *)
|
||||
type k = Ord.t
|
||||
|
||||
(** [t] is a key-value tree where each N has a key, value, left and right *)
|
||||
type ('k, 'v) t = L | N of k * 'v * (k, 'v) t * (k, 'v) t;;
|
||||
|
||||
(** [Not_found] exception if a given key cannot be found in the tree *)
|
||||
exception Not_found;;
|
||||
|
||||
(** empty tree *)
|
||||
let empty = L;;
|
||||
|
||||
(** [is_empty t] takes a kvtree [t] and checks if it is empty or not *)
|
||||
let is_empty t = t = L;;
|
||||
|
||||
(** [insert k v t] takes a comparator [], key [k], value [v],
|
||||
* and a kvtree [t] to insert the key and value [k, v] into the tree [t]. *)
|
||||
let rec insert k v t =
|
||||
match t with
|
||||
| L -> N (k, v, L, L)
|
||||
| N (k', v', l, r) when Ord.compare k k' < 0 ->
|
||||
N (k', v', insert k v l, r)
|
||||
| N (k', v', l, r) when Ord.compare k k' > 0 ->
|
||||
N (k', v', l, insert k v r)
|
||||
| N (k', _, l, r) when Ord.compare k k' = 0 ->
|
||||
N (k, v, l, r)
|
||||
| _ -> t;;
|
||||
|
||||
(** [find_opt k t] takes a key [k] and a kvtree [t] and returns
|
||||
* an Optional value found from the given key [k]. *)
|
||||
let rec find_opt k t =
|
||||
match t with
|
||||
| L -> None
|
||||
| N (k', _, l, _) when Ord.compare k k' < 0 ->
|
||||
find_opt k l
|
||||
| N (k', _, _, r) when Ord.compare k k' > 0 ->
|
||||
find_opt k r
|
||||
| N (_, v, _, _) -> Some v;;
|
||||
|
||||
(** [largest t] finds the largest key in a given kvtree [t]
|
||||
* and retursn the key value pair [k, v] *)
|
||||
let rec largest t =
|
||||
match t with
|
||||
| L -> failwith "largest: empty tree"
|
||||
| N (k, v, _, L) -> (k, v)
|
||||
| N (_, _, _, r) -> largest r;;
|
||||
|
||||
(** [smallest t] finds the smallest key in a given kvtree [t]
|
||||
* and retursn the key value pair [k, v] *)
|
||||
let rec smallest t =
|
||||
match t with
|
||||
| L -> failwith "smallest: empty tree"
|
||||
| N (k, v, L, _) -> (k, v)
|
||||
| N (_, _, l, _) -> smallest l;;
|
||||
|
||||
(** [delete k t] takes a key [k] and deletes it from a given
|
||||
* kvtree [t]. *)
|
||||
let rec delete k t =
|
||||
match t with
|
||||
| L -> L
|
||||
| N (k', v, l, r) when Ord.compare k k' < 0 ->
|
||||
N (k', v, delete k l, r)
|
||||
| N (k', v, l, r) when Ord.compare k k' > 0 ->
|
||||
N (k', v, l, delete k r)
|
||||
| N (_, _, l, L) -> l
|
||||
| N (_, _, L, r) -> r
|
||||
| N (_, _, l, r) ->
|
||||
let (ks, vs) = largest l in
|
||||
N (ks, vs, delete ks l, r);;
|
||||
|
||||
(** [of_list l] takes a list of pairs [l] and creates a
|
||||
* kvtree in the order specefied by the comparator [] to compare
|
||||
* keys *)
|
||||
let of_list l =
|
||||
List.fold_left (fun acc (k, v) -> insert k v acc) L l;;
|
||||
|
||||
(** [size t] takes a kvtree [t] and returns the size of the tree
|
||||
* i.e. number of Ns *)
|
||||
let rec size t =
|
||||
match t with
|
||||
| L -> 0
|
||||
| N (_, _, l, r) ->
|
||||
1 + size l + size r;;
|
||||
|
||||
(** [find k t] takes a key [k] and a kvtree [t] and returns
|
||||
* a value found from the given key [k]. *)
|
||||
let rec find k t =
|
||||
match t with
|
||||
| L -> raise Not_found
|
||||
| N (k', _, l, _) when Ord.compare k k' < 0 ->
|
||||
find k l
|
||||
| N (k', _, _, r) when Ord.compare k k' > 0 ->
|
||||
find k r
|
||||
| N (_, v, _, _) -> v;;
|
||||
|
||||
(** [to_list t] takes a key-value tree [t] and returns
|
||||
* a list representation of the key-value pairs *)
|
||||
let to_list t =
|
||||
let rec aux acc t =
|
||||
match t with
|
||||
| L -> acc
|
||||
| N (k, v, l, r) ->
|
||||
aux ((k, v) :: (aux acc r)) l
|
||||
in
|
||||
aux [] t;;
|
||||
|
||||
(** [to_string f t] takes a function [f] to "convert" a
|
||||
* key-value pair to a string, and applies that to all
|
||||
* key-value pairs in a given tree [t]. *)
|
||||
let rec to_string f t =
|
||||
match t with
|
||||
| L -> "#"
|
||||
| N (k, v, l, r) ->
|
||||
Printf.sprintf "^(%s, %s, %s)" (f (k, v)) (to_string f l) (to_string f r);;
|
||||
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
module type OrderedType = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
module type S = sig
|
||||
type k
|
||||
type ('k, 'v) t
|
||||
exception Not_found
|
||||
|
||||
val empty : (k, 'v) t
|
||||
val is_empty : (k, 'v) t -> bool
|
||||
val insert : k -> 'v -> (k, 'v) t -> (k, 'v) t
|
||||
val find_opt : k -> (k, 'v) t -> 'v option
|
||||
val delete : k -> (k, 'v) t -> (k, 'v) t
|
||||
val of_list : (k * 'v) list -> (k, 'v) t
|
||||
val size : (k, 'v) t -> int
|
||||
val find : k -> (k, 'v) t -> 'v
|
||||
val to_list : (k, 'v) t -> (k * 'v) list
|
||||
val to_string : ((k * 'v) -> string) -> (k, 'v) t -> string
|
||||
end
|
||||
|
||||
module Make(Ord: OrderedType) : S with type k = Ord.t
|
||||
@@ -0,0 +1,39 @@
|
||||
(* This is a minimal test file. Your program must pass these tests in order
|
||||
to get any credit for your work.
|
||||
In utop:
|
||||
#directory "_build";;
|
||||
#load "kvtree.cmo";;
|
||||
#use "tests.ml";;
|
||||
run ();;
|
||||
*)
|
||||
module M = Kvtree.Make(Int);;
|
||||
|
||||
let t = M.of_list [(3, "three"); (2, "two"); (7, "seven"); (6, "six"); (8, "eight")]
|
||||
let l = [(2, "two"); (3, "three"); (6, "six"); (7, "seven"); (8, "eight")]
|
||||
let s =
|
||||
"^(3, three, ^(2, two, #, #), ^(7, seven, ^(6, six, #, #), ^(8, eight, #, #)))"
|
||||
|
||||
let t2 = M.of_list [(3, 'a')]
|
||||
let s2 = "^(3, a, #, #)"
|
||||
|
||||
let t3 = M.insert 2 'b' t2
|
||||
let s3 = "^(3, a, ^(2, b, #, #), #)"
|
||||
|
||||
let t4 = M.of_list [(3, "3"); (7, "7"); (5, "5"); (6, "6"); (8, "8"); (9, "9")]
|
||||
let s4 = "^(3, 3, #, ^(7, 7, ^(5, 5, #, ^(6, 6, #, #)), ^(8, 8, #, ^(9, 9, #, #))))"
|
||||
let t5 = M.delete 7 t4
|
||||
let s5a = "^(3, 3, #, ^(6, 6, ^(5, 5, #, #), ^(8, 8, #, ^(9, 9, #, #))))"
|
||||
let s5b = "^(3, 3, #, ^(8, 8, ^(5, 5, #, ^(6, 6, #, #)), ^(9, 9, #, #)))"
|
||||
|
||||
let run () =
|
||||
assert (M.size t = 5);
|
||||
assert (M.find 7 t = "seven");
|
||||
assert (M.find_opt 7 t = Some "seven");
|
||||
assert (M.to_list t = l);
|
||||
assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t = s);
|
||||
assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %c" k v) t2 = s2);
|
||||
assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %c" k v) t3 = s3);
|
||||
assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t4 = s4);
|
||||
assert (
|
||||
let s = M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t5 in
|
||||
s = s5a || s = s5b)
|
||||
Reference in new issue
Block a user