diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index 5afd020f..97d1835a 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -435,6 +435,32 @@ match m with | [] -> 0 | _ :: t -> 1 + cardinal t + + let rec iter f m = + match m with + | [] -> () + | (k, v) :: t -> f k v; iter f t + + let rec fold f m acc = + match m with + | [] -> acc + | (k, v) :: t -> fold f t (f k v acc) + + let rec map f m = + match m with + | [] -> [] + | (k, v) :: t -> (k, f v) :: map f t + + let rec filter p m = + match m with + | [] -> [] + | (k, v) :: t -> + if p k v then (k, v) :: filter p t else filter p t + + let rec is_empty m = + match m with + | [] -> true + | _ -> false end end ;; @@ -472,6 +498,36 @@ match s with | [] -> 0 | _ :: t -> 1 + cardinal t + + let rec iter f s = + match s with + | [] -> () + | h :: t -> f h; iter f t + + let rec fold f s acc = + match s with + | [] -> acc + | h :: t -> fold f t (f h acc) + + let rec filter p s = + match s with + | [] -> [] + | h :: t -> if p h then h :: filter p t else filter p t + + let rec is_empty s = + match s with + | [] -> true + | _ -> false + + let rec union a b = + match b with + | [] -> a + | h :: t -> union (add h a) t + + let rec inter a b = + match a with + | [] -> [] + | h :: t -> if mem h b then h :: inter t b else inter t b end end") diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 0c2fdd5d..0a0e75ba 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1034,6 +1034,16 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 3303) (eval "(ocaml-run-program \"module IntOrd = struct let compare a b = compare a b end ;; module IntSet = Set.Make(IntOrd) ;; IntSet.mem 2 (IntSet.add 3 (IntSet.add 1 (IntSet.add 2 IntSet.empty)))\")") +;; ── Map/Set fold/iter/filter/union/inter ────────────────────── +(epoch 3400) +(eval "(ocaml-run-program \"module IntOrd = struct let compare a b = compare a b end ;; module IntMap = Map.Make(IntOrd) ;; let m = IntMap.add 1 10 (IntMap.add 2 20 IntMap.empty) ;; IntMap.fold (fun k v acc -> acc + v) m 0\")") +(epoch 3401) +(eval "(ocaml-run-program \"module IntOrd = struct let compare a b = compare a b end ;; module IntMap = Map.Make(IntOrd) ;; let m = IntMap.add 1 10 IntMap.empty ;; IntMap.is_empty m\")") +(epoch 3402) +(eval "(ocaml-run-program \"module IntOrd = struct let compare a b = compare a b end ;; module IntSet = Set.Make(IntOrd) ;; let a = IntSet.add 1 (IntSet.add 2 IntSet.empty) ;; let b = IntSet.add 2 (IntSet.add 3 IntSet.empty) ;; IntSet.elements (IntSet.union a b)\")") +(epoch 3403) +(eval "(ocaml-run-program \"module IntOrd = struct let compare a b = compare a b end ;; module IntSet = Set.Make(IntOrd) ;; let a = IntSet.add 1 (IntSet.add 2 (IntSet.add 3 IntSet.empty)) ;; let b = IntSet.add 2 (IntSet.add 3 (IntSet.add 4 IntSet.empty)) ;; IntSet.elements (IntSet.inter a b)\")") + EPOCHS OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1636,6 +1646,12 @@ check 3301 "Map.cardinal" '2' check 3302 "Set.elements sorted" '(1 2 3)' check 3303 "Set.mem" 'true' +# ── Map/Set fold/iter/filter/union/inter ─────────────────────── +check 3400 "Map.fold sum" '30' +check 3401 "Map.is_empty false" 'false' +check 3402 "Set.union" '(1 2 3)' +check 3403 "Set.inter" '(2 3)' + 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 d009b9d7..bc10a8fb 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -386,6 +386,9 @@ the "mother tongue" closure: OCaml → SX → OCaml. This means: _Newest first._ +- 2026-05-08 Phase 6 — Map/Set extensions: iter/fold/map/filter/ + is_empty + Set.union/inter (+4 tests, 422 total). Functor + bodies grow naturally — all in OCaml syntax. - 2026-05-08 Phase 6 — `Map.Make` / `Set.Make` functors written in OCaml (+4 tests, 418 total). Sorted association list / sorted list backed (linear ops, but correct). Both take an `Ord` module supplying