restructure + lecutre 07

This commit is contained in:
SowinskiBraeden committed 2026-02-19 11:59:58 -08:00
1 parent b8c19aa341
commit 7c3198fee4
96 files changed
+458 -4

No files matched your search

+114
View File
@@ -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
View File
@@ -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
View File
@@ -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()
(**/**)
+215
View File
@@ -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()
+36
View File
@@ -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()
(**/**)
+5
View File
@@ -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"
+12
View File
@@ -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.
+143
View File
@@ -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;;
+1
View File
@@ -0,0 +1 @@
records.ml: Array Printf Scanf Sys
Binary file not shown.
+5
View File
@@ -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
+5
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
monty burns
+160
View File
@@ -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;;
+139
View File
@@ -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
+23
View File
@@ -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
+39
View File
@@ -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)