structural equality, booleans, relational barriers for propagation
This commit is contained in:
parent
6cca0d17a1
commit
115b457173
4 changed files with 167 additions and 18 deletions
|
|
@ -75,3 +75,59 @@ export namespace Env {
|
|||
}
|
||||
}
|
||||
|
||||
export function equals(v1: Value, v2: Value): boolean {
|
||||
if (v1 === v2) return true; // Reference equality optimization
|
||||
if (v1.tag !== v2.tag) return false;
|
||||
switch (v1.tag) {
|
||||
case "number":
|
||||
return v1.value === (v2 as Extract<Value, { tag: "number" }>).value;
|
||||
case "string":
|
||||
return v1.value === (v2 as Extract<Value, { tag: "string" }>).value;
|
||||
case "tag":
|
||||
return v1.tag_name === (v2 as Extract<Value, { tag: "tag" }>).tag_name;
|
||||
case "tagged": {
|
||||
const other = v2 as Extract<Value, { tag: "tagged" }>;
|
||||
return v1.tag_name === other.tag_name && equals(v1.value, other.value);
|
||||
}
|
||||
case "tuple": {
|
||||
const other = v2 as Extract<Value, { tag: "tuple" }>;
|
||||
if (v1.values.length !== other.values.length) return false;
|
||||
for (let i = 0; i < v1.values.length; i++) {
|
||||
if (!equals(v1.values[i], other.values[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "record": {
|
||||
const other = v2 as Extract<Value, { tag: "record" }>;
|
||||
if (v1.fields.size !== other.fields.size) return false;
|
||||
for (const [key, val1] of v1.fields) {
|
||||
const val2 = other.fields.get(key);
|
||||
if (val2 === undefined || !equals(val1, val2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case "closure":
|
||||
// Philosophical/Mathematical barrier: throw error as requested
|
||||
throw ThrownRuntimeError.error({
|
||||
tag: "ClosureEqualityComparison",
|
||||
value0: v1.closure,
|
||||
value1: v2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Canonical bools are:
|
||||
// - True is `#T`
|
||||
// - False is `#F`
|
||||
// TODO: This is not a great design. Probably introducing completely new values would be better.
|
||||
export function forceBool(value: Value): boolean {
|
||||
if (value.tag === "tag") {
|
||||
if (value.tag_name === "T") return true;
|
||||
if (value.tag_name === "F") return false;
|
||||
}
|
||||
throw ThrownRuntimeError.error({
|
||||
tag: "NotABoolean",
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue