diff --git a/lib/ocaml/baseline/expected.json b/lib/ocaml/baseline/expected.json index ae92cffc..b86add6d 100644 --- a/lib/ocaml/baseline/expected.json +++ b/lib/ocaml/baseline/expected.json @@ -16,6 +16,7 @@ "factorial.ml": 3628800, "fraction.ml": 7, "frequency.ml": 5, + "grep_count.ml": 3, "hanoi.ml": 1023, "fizzbuzz.ml": 57, "list_ops.ml": 30, diff --git a/lib/ocaml/baseline/grep_count.ml b/lib/ocaml/baseline/grep_count.ml new file mode 100644 index 00000000..7b341f57 --- /dev/null +++ b/lib/ocaml/baseline/grep_count.ml @@ -0,0 +1,17 @@ +let rec str_contains s sub i = + let nl = String.length s in + let sl = String.length sub in + if i + sl > nl then false + else if String.sub s i sl = sub then true + else str_contains s sub (i + 1) + +let count_matching needle text = + let lines = String.split_on_char '\n' text in + List.fold_left (fun acc line -> + if str_contains line needle 0 then acc + 1 + else acc + ) 0 lines + +;; + +count_matching "fox" "the quick brown fox\nfox runs fast\nthe dog\nfoxes are clever" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index f4747065..23cb7bd0 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,13 @@ _Newest first._ binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree`) with insert + in-order traversal. Tests parametric ADT, recursive match, List.append, List.fold_left. +- 2026-05-09 Phase 5.1 — grep_count.ml baseline (substring-aware + line filter, 3 lines match). Defines a recursive `str_contains` + that walks the haystack with `String.sub` slices to find a needle + substring (real OCaml's `String.contains` only takes a char). + Splits text on `'\n'` then folds with the contains predicate. Test + text has 4 lines, 3 contain 'fox' (incl 'foxes'). 43 baseline + programs total. - 2026-05-09 Phase 5.1 — pretty_table.ml baseline (Buffer + Printf width specifiers, total length 64). Builds a 4-row scoreboard via Buffer + `Printf.sprintf "%-10s %4d\n"`. Each row is exactly 16