diff options
| author | DJ O'Leary <dijitol@proton.me> | 2025-12-08 03:09:04 +0100 |
|---|---|---|
| committer | DJ O'Leary <dijitol@proton.me> | 2025-12-08 03:09:04 +0100 |
| commit | 1387d0bda3acc66f14d5514bcc4da3634ede3645 (patch) | |
| tree | 350b4ca06326978afad49574e015537a00ce8ec6 | |
| parent | b8f1b26106c1c59a86e521edd7b9296ee57cbb48 (diff) | |
feat(range): implement range module for parsing ranges in the format "%d-%d"
| -rw-r--r-- | 2025/ocaml/lib/domain/range.ml | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/2025/ocaml/lib/domain/range.ml b/2025/ocaml/lib/domain/range.ml new file mode 100644 index 0000000..a1bdc00 --- /dev/null +++ b/2025/ocaml/lib/domain/range.ml @@ -0,0 +1,67 @@ +module M : sig + type t + + val of_string : string -> t option + (** [of_string s] is a range of integers if [s] is a string in the form ["%d-%d"] + or [None] otherwise. *) + + val collect : t -> int list + (** [collect range] is a fully realised range as a list. + Example: ["1-5" |> of_string |> collect] is the list [\[1;2;3;4;5\]]. + Example: ["5-1" |> of_string |> collect] is the list [\[5;4;3;2;1\]].*) + + val pp : t -> string + (** [pp range] is a pretty-printed version of the range. *) +end = struct + type t = int * int + + let of_string s = + Scanf.sscanf_opt s "%d-%d" (fun start finish -> (start, finish)) + + let rec collect (start, finish) = + let collected = + match Int.compare start finish with + | -1 -> + collect_range_aux Int.succ ( > ) [] (start, finish) + | 0 -> + [start] + | 1 -> + collect_range_aux Int.pred ( < ) [] (start, finish) + | _ -> + assert false + in + List.rev collected + + and collect_range_aux fn cmp lst (start, finish) = + if cmp start finish then lst + else collect_range_aux fn cmp (start :: lst) (fn start, finish) + + let pp (start, finish) = string_of_int start ^ "-" ^ string_of_int finish +end + +let%expect_test "incrementing range" = + match M.of_string "1-5" with + | None -> + [%expect.unreachable] + | Some range -> + let collected = M.collect range in + List.iter print_int collected ; + [%expect "12345"] + +let%expect_test "decrementing range" = + match M.of_string "5-1" with + | None -> + [%expect.unreachable] + | Some range -> + let collected = M.collect range in + List.iter print_int collected ; + [%expect "54321"] + +let%expect_test "one element range" = + match M.of_string "1-1" with + | None -> + [%expect.unreachable] + | Some range -> + let collected = M.collect range in + List.iter print_int collected ; + [%expect "1"] |
