spec: sets (make-set/set-add!/set-member?/union/intersection/etc)
Adds 13 set primitives to stdlib.sets. OCaml: SxSet as (string,value) Hashtbl keyed by inspect(val); JS: SxSet wrapping Map keyed by write-to-string. Structural equality — (make-set '(1 2)) contains 1. Includes union, intersection, difference, for-each, map. 33 tests in test-sets.sx, all pass on both JS and OCaml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-05-01T18:13:58Z";
|
||||
var SX_VERSION = "2026-05-01T18:42:40Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -184,6 +184,7 @@
|
||||
if (x._vector) return "vector";
|
||||
if (x._string_buffer) return "string-buffer";
|
||||
if (x._hash_table) return "hash-table";
|
||||
if (x._sxset) return "set";
|
||||
if (x._rational) return "rational";
|
||||
if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
|
||||
if (Array.isArray(x)) return "list";
|
||||
@@ -1096,6 +1097,60 @@
|
||||
};
|
||||
|
||||
|
||||
// stdlib.sets — structural sets keyed by write-to-string serialization
|
||||
function SxSet() { this.data = new Map(); this._sxset = true; }
|
||||
SxSet.prototype._type = "set";
|
||||
function sxSetKey(v) { return sxWriteVal(v, "write"); }
|
||||
function sxSetSeed(s, lst) {
|
||||
if (Array.isArray(lst)) lst.forEach(function(v) { s.data.set(sxSetKey(v), v); });
|
||||
return s;
|
||||
}
|
||||
PRIMITIVES["make-set"] = function() {
|
||||
var s = new SxSet();
|
||||
if (arguments.length > 0 && Array.isArray(arguments[0])) sxSetSeed(s, arguments[0]);
|
||||
return s;
|
||||
};
|
||||
PRIMITIVES["set?"] = function(v) { return v instanceof SxSet; };
|
||||
PRIMITIVES["set-add!"] = function(s, v) { s.data.set(sxSetKey(v), v); return NIL; };
|
||||
PRIMITIVES["set-member?"] = function(s, v) { return s.data.has(sxSetKey(v)); };
|
||||
PRIMITIVES["set-remove!"] = function(s, v) { s.data.delete(sxSetKey(v)); return NIL; };
|
||||
PRIMITIVES["set-size"] = function(s) { return s.data.size; };
|
||||
PRIMITIVES["set->list"] = function(s) { return Array.from(s.data.values()); };
|
||||
PRIMITIVES["list->set"] = function(lst) {
|
||||
var s = new SxSet();
|
||||
if (Array.isArray(lst)) lst.forEach(function(v) { s.data.set(sxSetKey(v), v); });
|
||||
return s;
|
||||
};
|
||||
PRIMITIVES["set-union"] = function(a, b) {
|
||||
var s = new SxSet();
|
||||
a.data.forEach(function(v, k) { s.data.set(k, v); });
|
||||
b.data.forEach(function(v, k) { s.data.set(k, v); });
|
||||
return s;
|
||||
};
|
||||
PRIMITIVES["set-intersection"] = function(a, b) {
|
||||
var s = new SxSet();
|
||||
a.data.forEach(function(v, k) { if (b.data.has(k)) s.data.set(k, v); });
|
||||
return s;
|
||||
};
|
||||
PRIMITIVES["set-difference"] = function(a, b) {
|
||||
var s = new SxSet();
|
||||
a.data.forEach(function(v, k) { if (!b.data.has(k)) s.data.set(k, v); });
|
||||
return s;
|
||||
};
|
||||
PRIMITIVES["set-for-each"] = function(s, fn) {
|
||||
s.data.forEach(function(v) { apply(fn, [v]); });
|
||||
return NIL;
|
||||
};
|
||||
PRIMITIVES["set-map"] = function(s, fn) {
|
||||
var out = new SxSet();
|
||||
s.data.forEach(function(v) {
|
||||
var r = apply(fn, [v]);
|
||||
out.data.set(sxSetKey(r), r);
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
|
||||
function isPrimitive(name) { return name in PRIMITIVES; }
|
||||
function getPrimitive(name) { return PRIMITIVES[name]; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user