Skip to content

Instantly share code, notes, and snippets.

@djmill0326
Created March 7, 2024 10:25
Show Gist options
  • Save djmill0326/72f55d61b7879d3e79fdae1adefd8c7c to your computer and use it in GitHub Desktop.
Save djmill0326/72f55d61b7879d3e79fdae1adefd8c7c to your computer and use it in GitHub Desktop.
some experiments
/* functional bullshit */
const narg = (f, n) => (...args) => f(...args.slice(0, n));
const argn = (f, n) => (...args) => f(...args.slice(n));
const nargn = (f, n, start) => (...args) => f(...args.slice(start, start + n));
const split = (f) => (...args) => args.forEach(x => f(x));
const spmap = (f) => (...args) => args.map(x => f(x));
const resv = (f, callback) => (...args) => callback(f(...args));
const side = (f, ...rest) => (...args) => resv(f, arg => rest.forEach(f => f(arg)))(...args);
const pipe = (f, ...rest) => rest.length
? (...args) => rest.reduce((result, f) => f(result), f(...args))
: (...args) => f(...args);
// this doesn't work, and i'm actually convinced it's a bug in the node runtime
const plumb = (...flow) => (source) => source(pipe(...flow));
/* object fuckery */
const kvnorm = (x) => x.length ? x.flatMap(value => destroy(value)) : Object.entries(x).flatMap(kv => ({ $: kv[0], x: destroy(kv[1]) }));
const destroy = (x) => typeof x === "boolean" || typeof x === "number" || typeof x === "string" || typeof x === "function" || typeof x === "bigint" || x === undefined || x === null ? x : kvnorm(x);
const arrcmp = (a, b) => a.length !== b.length ? true : a.find((x, i) => x !== b[i]) !== undefined;
// DOES NOT WORK (yet)
const cmprimitive = (a, b) => arrcmp(destroy(a), destroy(b));
const objpluck = f => (x, visited=null, ref=null) => {
if (!visited) {
visited = new Map();
ref = { x:-1 };
} else if ((id = visited.get(x)) !== undefined) return `<recursive *${id}>`;
visited.set(x, ++ref.x);
if (x.map) return x.map(value => f(value, visited, ref));
else {
const object = {};
for (const key in x) object[key] = f(x[key], visited, ref);
return object;
}
}
const cerealize = (x, visited=null, ref=null) => typeof x === "function" || typeof x === "symbol" || typeof x === "bigint" ? x.toString()
:( typeof x === "number" || typeof x === "string" || typeof x === "boolean" || x === undefined || x === null ? x
: objpluck(cerealize)(x, visited, ref));
/* reactive nonsense */
class Resolved {
resolve () {
throw new Error("not implemented");
}
update (value) {
throw new Error("not implemented");
}
}
class Value extends Resolved {
#value;
constructor(value) {
super();
this.#value = value;
}
raw() {
return this.#value;
}
resolve() {
return this.#value;
}
update(value) {
if(this.on_update) this.on_update(value, this.#value);
this.#value = value;
}
}
class Memo extends Resolved {
#value;
#cache;
constructor(value) {
super();
this.#value = value instanceof Value ? value : new Value(value);
this.#cache = this.#value.resolve();
}
resolve() {
return this.#cache;
}
update(value, force=false) {
if (force || value !== this.#value.raw()) this.#value.update(value);
const previous = this.#cache;
this.#cache = this.#value.resolve();
if(this.on_update) this.on_update(this.#cache, previous);
}
}
class Broadcast {
#open = new Map();
send(data) {
this.#open.forEach(sink => sink(data, this));
}
notify(id, data) {
const sink = this.#open.get(id);
if (sink) return sink(data);
}
open(sink) {
const id = this.#open.size << 1 + 1;
this.#open.set(id, sink);
return id;
}
close(port) {
return this.#open.delete(port);
}
}
class Active extends Memo {
#proxy = new Broadcast();
constructor(value) {
super(value);
}
on_update(value, previous) {
this.#proxy.send(value, previous);
}
subscribe(callback) {
return this.#proxy.open(callback);
}
unsub(id) {
return this.#proxy.close(id);
}
}
class Conscious extends Active {
on_update(value, previous) {
if (value !== previous) super.on_update(value);
}
}
const Reactive = (value, diff=true) => diff ? new Conscious(value) : new Active(value);
/* insufficient test cases */
const serialize_test = {
hi: "there",
test2: []
};
serialize_test.broken = serialize_test;
serialize_test.test2.push(serialize_test);
serialize_test.test2.push(serialize_test.test2);
serialize_test.broken.test3 = serialize_test.test2[1];
console.warn("--- serialize/reactive test ---");
const reactive_test = Reactive();
const handle = reactive_test.subscribe(pipe(narg(cerealize, 1), x => console.debug(">", x)));
reactive_test.update("hello, world!");
reactive_test.update({ x: 777, f: (kill) => yourself, serial: "eyes" });
reactive_test.update(function hello() {});
reactive_test.update("goodbye, world :(");
// reactive_test.unsub(handle);
reactive_test.update(serialize_test);
console.warn("--- visitor test ---");
const test_a = [{ hi: { nested: "x" } }, 0, "b", true, [false, { balls: 0 }]];
const test_b = [{ hi: { nested: "x" } }, 0, "b", true, [false, { balls: 0 }]];
// test_a.push(test_a);
// test_a[0].hi.nested = "x";
// test_a[1] = 1;
// test_a[4][0] = true;
console.log("changed:", cmprimitive(test_a, test_b));
console.log(destroy(test_a));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment