diff --git a/lib/haskell/map.sx b/lib/haskell/map.sx index 6d30a316..8f4cb092 100644 --- a/lib/haskell/map.sx +++ b/lib/haskell/map.sx @@ -419,3 +419,102 @@ (fn (k v acc) (cond ((p k v) (hk-map-insert k v acc)) (:else acc))) hk-map-empty m))) + +(define + hk-map-adjust + (fn + (f k m) + (cond + ((hk-map-empty? m) m) + (:else + (let + ((mk (hk-map-key m))) + (cond + ((< k mk) + (hk-map-node + mk + (hk-map-val m) + (hk-map-adjust f k (hk-map-left m)) + (hk-map-right m))) + ((> k mk) + (hk-map-node + mk + (hk-map-val m) + (hk-map-left m) + (hk-map-adjust f k (hk-map-right m)))) + (:else + (hk-map-node + mk + (f (hk-map-val m)) + (hk-map-left m) + (hk-map-right m))))))))) + +(define + hk-map-insert-with + (fn + (f k v m) + (cond + ((hk-map-empty? m) (hk-map-singleton k v)) + (:else + (let + ((mk (hk-map-key m))) + (cond + ((< k mk) + (hk-map-balance + mk + (hk-map-val m) + (hk-map-insert-with f k v (hk-map-left m)) + (hk-map-right m))) + ((> k mk) + (hk-map-balance + mk + (hk-map-val m) + (hk-map-left m) + (hk-map-insert-with f k v (hk-map-right m)))) + (:else + (hk-map-node + mk + (f v (hk-map-val m)) + (hk-map-left m) + (hk-map-right m))))))))) + +(define + hk-map-insert-with-key + (fn + (f k v m) + (cond + ((hk-map-empty? m) (hk-map-singleton k v)) + (:else + (let + ((mk (hk-map-key m))) + (cond + ((< k mk) + (hk-map-balance + mk + (hk-map-val m) + (hk-map-insert-with-key f k v (hk-map-left m)) + (hk-map-right m))) + ((> k mk) + (hk-map-balance + mk + (hk-map-val m) + (hk-map-left m) + (hk-map-insert-with-key f k v (hk-map-right m)))) + (:else + (hk-map-node + mk + (f k v (hk-map-val m)) + (hk-map-left m) + (hk-map-right m))))))))) + +(define + hk-map-alter + (fn + (f k m) + (let + ((look (hk-map-lookup k m))) + (let + ((res (f look))) + (cond + ((= (first res) "Nothing") (hk-map-delete k m)) + (:else (hk-map-insert k (nth res 1) m))))))) diff --git a/plans/haskell-completeness.md b/plans/haskell-completeness.md index 45385681..cde89129 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -187,7 +187,7 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. - [x] Bulk operations: `fromList`, `toList`, `toAscList`, `keys`, `elems`. - [x] Combining: `unionWith`, `intersectionWith`, `difference`. - [x] Transforming: `foldlWithKey`, `foldrWithKey`, `mapWithKey`, `filterWithKey`. -- [ ] Updating: `adjust`, `insertWith`, `insertWithKey`, `alter`. +- [x] Updating: `adjust`, `insertWith`, `insertWithKey`, `alter`. - [ ] Module wiring: `import Data.Map` and `import qualified Data.Map as Map` resolve to the `map.sx` namespace dict in the eval import handler. - [ ] Unit tests in `lib/haskell/tests/map.sx` (≥ 20 tests: empty, singleton, @@ -304,6 +304,12 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. _Newest first._ +**2026-05-07** — Phase 11 updating (adjust/insertWith/insertWithKey/alter): +- `adjust` recurses to find the key, replaces value with `f(v)`; no-op when + missing. `insertWith` and `insertWithKey` recurse with rebalance and use + `f new old` (or `f k new old`) when the key exists. `alter` is the most + general, implemented as `lookup → f → either delete or insert`. + **2026-05-07** — Phase 11 transforming (foldlWithKey/foldrWithKey/mapWithKey/filterWithKey): - Folds traverse in-order. `foldlWithKey f acc m` walks left → key/val → right threading the accumulator, so left-folding `(\acc k v -> acc ++ k ++ v)` over