From 98ba772acd24a9b06446da6bb9df57678dd31da3 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 9 May 2026 06:35:42 +0000 Subject: [PATCH] ocaml: phase 6 List.equal / List.compare (+5 tests, 589 total) Both take an inner predicate / comparator and walk both lists in lockstep: equal eq a b short-circuits on first mismatch compare cmp a b -1 if a is a strict prefix 1 if b is 0 if both empty otherwise first non-zero element comparison Mirrors real OCaml's signatures. List.equal (=) [1;2;3] [1;2;3] = true List.equal (=) [1;2;3] [1;2;4] = false List.compare compare [1;2;3] [1;2;4] = -1 List.compare compare [1;2] [1;2;3] = -1 List.compare compare [] [] = 0 --- lib/ocaml/runtime.sx | 18 ++++++++++++++++++ lib/ocaml/test.sh | 19 +++++++++++++++++++ plans/ocaml-on-sx.md | 7 +++++++ 3 files changed, 44 insertions(+) diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index a9e204fb..b9ac30d9 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -194,6 +194,24 @@ | Some v -> Some v | None -> find_map f t + let rec equal eq a b = + match a with + | [] -> (match b with [] -> true | _ -> false) + | h :: t -> + (match b with + | [] -> false + | h2 :: t2 -> if eq h h2 then equal eq t t2 else false) + + let rec compare cmp a b = + match a with + | [] -> (match b with [] -> 0 | _ -> -1) + | h :: t -> + (match b with + | [] -> 1 + | h2 :: t2 -> + let c = cmp h h2 in + if c <> 0 then c else compare cmp t t2) + let rec combine xs ys = match xs with | [] -> (match ys with diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 7d040fe7..76587eac 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1460,6 +1460,18 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 5214) (eval "(ocaml-run \"Option.compare compare (Some 5) (Some 3)\")") +;; ── List.equal / List.compare ──────────────────────────────── +(epoch 5220) +(eval "(ocaml-run \"List.equal (=) [1;2;3] [1;2;3]\")") +(epoch 5221) +(eval "(ocaml-run \"List.equal (=) [1;2;3] [1;2;4]\")") +(epoch 5222) +(eval "(ocaml-run \"List.compare compare [1;2;3] [1;2;4]\")") +(epoch 5223) +(eval "(ocaml-run \"List.compare compare [1;2] [1;2;3]\")") +(epoch 5224) +(eval "(ocaml-run \"List.compare compare [] []\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -2322,6 +2334,13 @@ check 5212 "Option.equal Some 1 Some 1" 'true' check 5213 "Option.equal Some 1 None" 'false' check 5214 "Option.compare Some 5 Some 3" '1' +# ── List.equal / List.compare ─────────────────────────────────── +check 5220 "List.equal [1;2;3] [1;2;3]" 'true' +check 5221 "List.equal [1;2;3] [1;2;4]" 'false' +check 5222 "List.compare [1;2;3] [1;2;4]" '-1' +check 5223 "List.compare [1;2] [1;2;3]" '-1' +check 5224 "List.compare [] []" '0' + 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 dc5c66fc..0bd9a913 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 6 — List.equal / List.compare (+5 tests, 589 + total). Both take an inner predicate / comparator and walk both + lists in lockstep. equal short-circuits on first mismatch. + compare returns -1 if a is a strict prefix, 1 if b is, 0 if both + empty, otherwise the first non-zero element comparison. Mirrors + real OCaml's signatures: `List.equal eq a b`, `List.compare cmp + a b`. - 2026-05-09 Phase 6 — Bool module + Option.equal / Option.compare (+5 tests, 584 total). Bool: equal, compare (false < true via if ladder), to_string, of_string, not_, to_int. Option additions