90 lines
2.2 KiB
JavaScript
90 lines
2.2 KiB
JavaScript
import { deepEqual } from "../util/util.js";
|
|
import { inspect } from "node:util";
|
|
|
|
// a -> Value<a>
|
|
export const newLiteral = val => ({
|
|
kind: "literal",
|
|
out: val,
|
|
[inspect.custom]: (depth, options, inspect) => `newLiteral(${inspect(val)})`,
|
|
});
|
|
|
|
// Slot<a> -> Value<a>
|
|
export const read = slot => ({
|
|
kind: "read",
|
|
slot,
|
|
out: slot.value.out,
|
|
[inspect.custom]: (depth, options, inspect) => `read(${inspect(slot)})`,
|
|
});
|
|
|
|
// Value<a> -> Value<a -> b> -> Value<b>
|
|
export const transform = input => fn => {
|
|
const output = fn.out(input.out);
|
|
// const _inspect = (depth, options, inspect) => `transform(${inspect(input)}, ${inspect(fn)})`;
|
|
if (input.kind === "literal") {
|
|
// optimization: sandwich everything together
|
|
return {
|
|
kind: "literal",
|
|
out: output,
|
|
// [inspect.custom]: _inspect,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: "transform",
|
|
in: input,
|
|
fn,
|
|
out: output,
|
|
// [inspect.custom]: _inspect,
|
|
};
|
|
}
|
|
};
|
|
|
|
// Value<a> -> Set<Slot<Top>>
|
|
export const getReadDependencies = value => {
|
|
if (value.kind === "literal") {
|
|
return new Set();
|
|
}
|
|
else if (value.kind === "read") {
|
|
return new Set([value.slot]);
|
|
}
|
|
else if (value.kind === "transform") {
|
|
return new Set([
|
|
...getReadDependencies(value.in),
|
|
...getReadDependencies(value.fn),
|
|
]);
|
|
}
|
|
};
|
|
|
|
// for debugging
|
|
export const verifyValue = (value, indent = 0) => {
|
|
let success = true;
|
|
const printIndent = (...args) => {
|
|
console.log(" ".repeat(indent * 2), ...args);
|
|
};
|
|
const compare = (a, b, kind) => {
|
|
if (typeof a === 'function' && typeof b === 'function') {
|
|
printIndent("note: cannot compare functions", `(${kind})`);
|
|
}
|
|
else if (deepEqual(a, b)) {
|
|
printIndent(`ok (${kind})`);
|
|
}
|
|
else {
|
|
printIndent(`bad (${kind})`);
|
|
success = false;
|
|
}
|
|
};
|
|
if (value.kind === "literal") {
|
|
compare(1, 1, "literal");
|
|
}
|
|
else if (value.kind === "read") {
|
|
compare(value.out, value.slot.value.out, "read");
|
|
}
|
|
else if (value.kind === "transform") {
|
|
compare(value.fn.out(value.in.out),
|
|
value.out, "transform");
|
|
|
|
success &= verifyValue(value.in, indent + 1);
|
|
success &= verifyValue(value.fn, indent + 1);
|
|
}
|
|
return success;
|
|
};
|