65 lines
1.9 KiB
JavaScript
65 lines
1.9 KiB
JavaScript
import { Unit } from "../primitives/types.js";
|
||
import { unit } from "../primitives/unit.js";
|
||
import { capitalizeFirstLetter } from "../util/util.js";
|
||
import { constructorProduct, getLeft, getRight } from "./product.js";
|
||
import { fnType, prodType } from "./types.js";
|
||
|
||
// 'fields' is an array of (name: string, type: Type) pairs.
|
||
// e.g.:
|
||
// [{l: "x", r: Double}, {l: "y", r: Double}]
|
||
// results in the type (Double × (Double × Unit))
|
||
export const structType = fields => {
|
||
if (fields.length === 0) {
|
||
return Unit;
|
||
}
|
||
const [field, ...rest] = fields;
|
||
const fieldType = getRight(field);
|
||
return prodType(fieldType)(structType(rest));
|
||
};
|
||
|
||
export const makeConstructor = fields => {
|
||
const internal = (nParams, ret) => {
|
||
if (nParams === 0) {
|
||
const result = ret(unit);
|
||
return result;
|
||
}
|
||
return nextParam => {
|
||
const wrappedName = 'wrapped_' + ret.name;
|
||
const newRet = {
|
||
[wrappedName]: inner => constructorProduct(nextParam)(ret(inner)),
|
||
}[wrappedName];
|
||
return internal(nParams-1, newRet);
|
||
}
|
||
};
|
||
const id = x => x;
|
||
return internal(fields.length, id);
|
||
};
|
||
|
||
export const makeConstructorType = type => fields => {
|
||
if (fields.length === 0) {
|
||
return type;
|
||
}
|
||
const [field, ...rest] = fields;
|
||
const fieldType = getRight(field);
|
||
return fnType(fieldType)(makeConstructorType(rest));
|
||
};
|
||
|
||
export const makeGetters = fields => {
|
||
if (fields.length === 0) {
|
||
return [];
|
||
}
|
||
const [field, ...rest] = fields;
|
||
const fieldName = getLeft(field);
|
||
const getterName = `get${capitalizeFirstLetter(fieldName)}`;
|
||
return [
|
||
{ [getterName]: obj => getLeft(obj) }[getterName],
|
||
...makeGetters(rest).map(getter => ({[getter.name]: obj => getter(getRight(obj))}[getter.name])),
|
||
];
|
||
};
|
||
|
||
export const makeGettersTypes = type => fields => {
|
||
return fields.map(field => {
|
||
const fieldType = getRight(field);
|
||
return fnType(type)(fieldType);
|
||
});
|
||
};
|