Files
comp3958/lab02/lab2.ml
T
2026-02-05 16:11:52 -08:00

182 lines
5.3 KiB
OCaml

(** [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()
(**/**)