From 8af36306254ae9dd0c45fc08f7f78afc3bfd9794 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 9 May 2026 01:19:28 +0000 Subject: [PATCH] ocaml: phase 6 String.iter/iteri/fold_left/fold_right/to_seq/of_seq (+3 tests, 501 total) Six new String functions, all in OCaml syntax inside runtime.sx: iter : index-walk with side-effecting f iteri : iter with index fold_left : thread accumulator left-to-right fold_right: thread accumulator right-to-left to_seq : return a char list (lazy in real OCaml; eager here) of_seq : concat a char list back to a string Round-trip: String.of_seq (List.rev (String.to_seq "hello")) = "olleh" Note: real OCaml's Seq is lazy. We return a plain list because the existing stdlib already provides exhaustive list operations and we don't yet have lazy sequences. If a baseline needs Seq.unfold or similar, we'll graduate to a proper Seq module then. --- lib/ocaml/runtime.sx | 37 +++++++++++++++++++++++++++++++++++++ lib/ocaml/test.sh | 13 +++++++++++++ plans/ocaml-on-sx.md | 7 +++++++ 3 files changed, 57 insertions(+) diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index cd5eea0f..52d9d2ec 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -374,6 +374,43 @@ else aux (i + 1) (acc ^ f (_string_get s i)) in aux 0 \"\" + let iter f s = + let rec aux i = + if i >= _string_length s then () + else (f (_string_get s i); aux (i + 1)) + in + aux 0 + let iteri f s = + let rec aux i = + if i >= _string_length s then () + else (f i (_string_get s i); aux (i + 1)) + in + aux 0 + let fold_left f init s = + let rec aux i acc = + if i >= _string_length s then acc + else aux (i + 1) (f acc (_string_get s i)) + in + aux 0 init + let fold_right f s init = + let rec aux i acc = + if i < 0 then acc + else aux (i - 1) (f (_string_get s i) acc) + in + aux (_string_length s - 1) init + let to_seq s = + let rec aux i = + if i >= _string_length s then [] + else _string_get s i :: aux (i + 1) + in + aux 0 + let of_seq xs = + let rec aux ys acc = + match ys with + | [] -> acc + | h :: t -> aux t (acc ^ h) + in + aux xs \"\" end ;; module Bytes = struct diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 326fa9f1..f8c1467a 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1240,6 +1240,14 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 4971) (eval "(ocaml-run \"Format.asprintf \\\"%s=%d\\\" \\\"n\\\" 7\")") +;; ── String.iter / fold / seq ───────────────────────────────── +(epoch 4980) +(eval "(ocaml-run \"let n = ref 0 in String.iter (fun c -> n := !n + Char.code c) \\\"abc\\\"; !n\")") +(epoch 4981) +(eval "(ocaml-run \"String.fold_left (fun acc c -> acc + Char.code c) 0 \\\"hi\\\"\")") +(epoch 4982) +(eval "(ocaml-run \"String.of_seq (List.rev (String.to_seq \\\"hello\\\"))\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1968,6 +1976,11 @@ check 4961 "lazy memoization counter=1" '8401' check 4970 "Format.sprintf %d" '"99"' check 4971 "Format.asprintf %s=%d" '"n=7"' +# ── String.iter / fold_left / seq ─────────────────────────────── +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"' + 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 0e87915f..b19573db 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 — 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 + + side-effecting `f`, fold_left / fold_right thread an accumulator, + to_seq returns a char list, of_seq concats a char list back to a + string. Round-trip: `String.of_seq (List.rev (String.to_seq + "hello"))` → "olleh". - 2026-05-09 Phase 5.1 — frequency.ml baseline + Format module alias (+2 tests, 498 total). frequency.ml builds a Hashtbl of char→count via `Hashtbl.find_opt` + `Hashtbl.replace` inside a `for` loop, then