diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index 52d9d2ec..58fea697 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -158,6 +158,26 @@ let stable_sort = sort + let rec sort_uniq cmp xs = + let sorted = sort cmp xs in + let rec dedup ys = + match ys with + | [] -> [] + | [x] -> [x] + | a :: b :: rest -> + if cmp a b = 0 then dedup (b :: rest) + else a :: dedup (b :: rest) + in + dedup sorted + + let rec find_map f xs = + match xs with + | [] -> None + | h :: t -> + match f h with + | Some v -> Some v + | None -> find_map f t + let rec combine xs ys = match xs with | [] -> (match ys with diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index f8c1467a..39414caf 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1248,6 +1248,12 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 4982) (eval "(ocaml-run \"String.of_seq (List.rev (String.to_seq \\\"hello\\\"))\")") +;; ── List.sort_uniq / List.find_map ─────────────────────────── +(epoch 4990) +(eval "(ocaml-run \"List.sort_uniq compare [3;1;2;1;3;2;4]\")") +(epoch 4991) +(eval "(ocaml-run \"List.find_map (fun x -> if x > 5 then Some (x * 2) else None) [1;2;3;6;7]\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1981,6 +1987,10 @@ check 4980 "String.iter sum codes abc" '294' check 4981 "String.fold_left sum hi" '209' check 4982 "String.of_seq (rev to_seq)" '"olleh"' +# ── List.sort_uniq / List.find_map ────────────────────────────── +check 4990 "sort_uniq dedupes & sorts" '(1 2 3 4)' +check 4991 "find_map first >5 doubled" '("Some" 12)' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index b19573db..51ed0288 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,11 @@ _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 6 — List.sort_uniq / List.find_map (+2 tests, 503 + total). sort_uniq sorts then dedups consecutive equals. find_map + walks until the user fn returns `Some v` and returns it (or `None` + on empty/all-None). Closes two of the most-asked-for list ops; both + defined in OCaml syntax in runtime.sx. - 2026-05-09 Phase 6 — String.iter / iteri / fold_left / fold_right / to_seq / of_seq (+3 tests, 501 total). All implemented in OCaml syntax inside the runtime stdlib; iter / iteri walk via index +