dope2/lib/compare/structures.js

132 lines
4.9 KiB
JavaScript

// Total ordering of composed types
import { compareBools, compareDoubles, compareStrings } from "./primitives.js"
import { get, length as lengthLs } from "../structures/list.js";
import { read as readSet, length as lengthSet, first as firstSet } from "../structures/set.js";
import { read as readDict, length as lengthDict, first as firstDict } from "../structures/dict.js";
import { getLeft, getRight } from "../structures/product.js";
import { match } from "../structures/sum.js";
export const compareFunctions = _compareInput => _compareOutput => x => y => {
// dirty but does the job
return compareStrings(x.toString())(y.toString());
}
export const compareLists = compareElems => x => y => {
return compareDoubles(lengthLs(x))(lengthLs(y))
|| (() => {
for (let i=0; i<lengthLs(x); i++) {
const elemCmp = compareElems(get(x)(i))(get(y)(i));
if (elemCmp !== 0) {
return elemCmp;
}
}
return 0;
})();
};
export const compareProducts = compareLeft => compareRight => x => y => {
return compareLeft (getLeft (x))(getLeft (y))
|| compareRight(getRight(x))(getRight(y));
};
export const compareSums = compareLeft => compareRight => x => y => {
// console.log("compareSums...", x, y)
return match(x)
(leftValueX => match(y)
(leftValueY => compareLeft(leftValueX)(leftValueY)) // both are left
((_rightValueY) => {
// console.log("x is 'left' and y is 'right' => x < y")
return -1;
}) // x is 'left' and y is 'right' => x < y
)
(rightValueX => match(y)
(_leftValueY => {
// console.log("x is 'right' and y is 'left' => x > y");
return 1;
}) // x is 'right' and y is 'left' => x > y
(rightValueY => compareRight(rightValueX)(rightValueY)) // both are right
);
};
export const compareSets = compareElems => x => y => {
return compareDoubles(lengthSet(x))(lengthSet(y))
|| (() => {
// sets have same size -> iterate over both sets and compare their elements pairwise
// because of the underlying red-black tree, iteration happens in ordered fashion
const iterate = iterX => entryY =>
match(readSet(iterX))
(entryX =>
match(readSet(entryY))
(resultY => compareElems
(getLeft(entryX))
(getLeft(resultY))
|| iterate
(getRight(entryX))
(getRight(resultY)))
(_ => 0))
(_ => 0); // we made it, sets are equal
return iterate(firstSet(x))(firstSet(y));
})();
};
export const compareDicts = compareKeys => compareValues => x => y => {
return compareDoubles(lengthDict(x))(lengthDict(y))
|| (() => {
// dicts have same size -> iterate over both and compare their entries pairwise
// because of the underlying red-black tree, iteration happens in ordered fashion
const iterate = iterX => iterY =>
match(readDict(iterX))
(entryX =>
match(readDict(iterY))
(entryY => compareKeys
(getLeft(getLeft(entryX)))
(getLeft(getLeft(entryY)))
|| compareValues
(getRight(getLeft(entryX)))
(getRight(getLeft(entryY)))
|| iterate
(getRight(entryX))
(getRight(entryY)))
(_ => 0))
(_ => 0); // we made it, dicts are equal
return iterate(firstDict(x))(firstDict(y));
})();
};
export const compareSetIterators = compareElems => x => y => {
// first compare the sets the iterators belong to,
// if the iterators belong to different sets, then they surely are not equal:
const ord = compareSets(compareElems)(x.tree)(y.tree);
if (ord !== 0) {
return ord; // sets differ
}
// sets are equal...
const xIsValid = x !== undefined && x.valid;
const yIsValid = y !== undefined && y.valid;
const ord2 = compareBools(xIsValid)(yIsValid);
if (ord2 !== 0) {
return ord2; // one is valid, the other is not
}
// both iterators are valid...
return compareElems(x.key)(y.key);
};
export const compareDictIterators = compareKeys => compareValues => x => y => {
// first compare the sets the iterators belong to,
// if the iterators belong to different sets, then they surely are not equal:
const ord = compareDicts(compareKeys)(compareValues)(x.tree)(y.tree);
if (ord !== 0) {
return ord; // sets differ
}
// sets are equal...
const xIsValid = x !== undefined && x.valid;
const yIsValid = y !== undefined && y.valid;
const ord2 = compareBools(xIsValid)(yIsValid);
if (ord2 !== 0) {
return ord2; // one is valid, the other is not
}
// both iterators are valid...
return compareKeys (x.key )(y.key )
|| compareValues(x.value)(y.value)
};