simplify 'struct'
This commit is contained in:
parent
43342e90d4
commit
366b1ec4e0
3 changed files with 57 additions and 52 deletions
|
|
@ -1,33 +1,30 @@
|
|||
import { unit } from "../primitives/unit.js";
|
||||
import { capitalizeFirstLetter } from "../util/util.js";
|
||||
import { newProduct, getLeft, getRight } from "./product.js";
|
||||
|
||||
export const makeConstructor = nParams => {
|
||||
const internal = (nParams, ret) => {
|
||||
if (nParams === 0) {
|
||||
export const makeConstructor = fieldNames => {
|
||||
const internal = (fieldNames, ret) => {
|
||||
if (fieldNames.length === 0) {
|
||||
const result = ret(unit);
|
||||
return result;
|
||||
}
|
||||
return nextParam => {
|
||||
const wrappedName = 'wrapped_' + ret.name;
|
||||
const [fieldName, ...rest] = fieldNames;
|
||||
const wrappedName = 'ctor_' + fieldName;
|
||||
const newRet = {
|
||||
[wrappedName]: inner => newProduct(nextParam)(ret(inner)),
|
||||
[wrappedName]: inner => ({[fieldName]: nextParam, ...ret(inner)}),
|
||||
}[wrappedName];
|
||||
return internal(nParams-1, newRet);
|
||||
return internal(rest, newRet);
|
||||
}
|
||||
};
|
||||
const id = x => x;
|
||||
return internal(nParams, id);
|
||||
return internal(fieldNames, id);
|
||||
};
|
||||
|
||||
export const makeGetters = fieldNames => {
|
||||
if (fieldNames.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const [fieldName, ...rest] = fieldNames;
|
||||
return fieldNames.map(fieldName => {
|
||||
const getterName = `get${capitalizeFirstLetter(fieldName)}`;
|
||||
return [
|
||||
{ [getterName]: obj => getLeft(obj) }[getterName],
|
||||
...makeGetters(rest).map(getter => ({[getter.name]: obj => getter(getRight(obj))}[getter.name])),
|
||||
];
|
||||
return {
|
||||
[getterName]: obj => obj[fieldName],
|
||||
}[getterName];
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,40 +1,14 @@
|
|||
import { getDefaultTypeParser } from "../parser/type_parser.js";
|
||||
import { newDynamic } from "../primitives/dynamic.js";
|
||||
import { Type, Unit } from "../primitives/primitive_types.js";
|
||||
import { zip } from "../util/util.js";
|
||||
import { map } from "./list.js";
|
||||
import { getLeft, getRight } from "./product.js";
|
||||
import { makeConstructor, makeGetters } from "./struct.js";
|
||||
import { fnType, prodType } from "./type_constructors.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, rootSelf) => {
|
||||
// console.log("structType..", fields);
|
||||
if (fields.length === 0) {
|
||||
return Unit;
|
||||
}
|
||||
const [field, ...rest] = fields;
|
||||
const fieldType = getRight(field);
|
||||
return prodType
|
||||
(self => {
|
||||
// console.log("requested left type (of structType)")
|
||||
return fieldType(rootSelf || self);
|
||||
})
|
||||
(self => {
|
||||
// console.log("requested right type (of structType)")
|
||||
return structType(rest, self);
|
||||
});
|
||||
};
|
||||
import { fnType } from "./type_constructors.types.js";
|
||||
|
||||
export const makeConstructorType = type => fields => {
|
||||
if (fields.length === 0) {
|
||||
return type;
|
||||
// return structType(fields);
|
||||
}
|
||||
const [field, ...rest] = fields;
|
||||
const fieldType = getRight(field);
|
||||
|
|
@ -42,7 +16,6 @@ export const makeConstructorType = type => fields => {
|
|||
};
|
||||
|
||||
export const makeGettersTypes = type => fields => {
|
||||
// const type = structType(fields);
|
||||
return fields.map(field => {
|
||||
const fieldType = getRight(field);
|
||||
return fnType(_ => type)(_ => fieldType);
|
||||
|
|
@ -51,14 +24,11 @@ export const makeGettersTypes = type => fields => {
|
|||
|
||||
export const makeModuleStruct = type => fields => {
|
||||
const fieldNames = map(fields)(getLeft);
|
||||
// const type = structType(fields);
|
||||
const ctor = makeConstructor(fields.length);
|
||||
const ctorType = makeConstructorType(fields);
|
||||
const getterTypes = makeGettersTypes(fields);
|
||||
const ctor = makeConstructor(fieldNames);
|
||||
const ctorType = makeConstructorType(type)(fields);
|
||||
const getterTypes = makeGettersTypes(type)(fields);
|
||||
const getters = makeGetters(fieldNames);
|
||||
const module = [
|
||||
// ["type", newDynamic(type)(Type)],
|
||||
|
||||
// constructor
|
||||
["ctor", newDynamic(ctor)(ctorType)],
|
||||
|
||||
|
|
@ -72,6 +42,6 @@ export const makeModuleStruct = type => fields => {
|
|||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleStruct = [
|
||||
["structType" , newDynamic(structType )(mkType("[String*Type] -> Type" ))],
|
||||
// ["structType" , newDynamic(structType )(mkType("[String*Type] -> Type" ))],
|
||||
["makeModuleStruct", newDynamic(makeModuleStruct)(mkType("[String*Type] -> [Dynamic]"))],
|
||||
];
|
||||
|
|
|
|||
38
tests/struct.js
Normal file
38
tests/struct.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import assert from "node:assert";
|
||||
|
||||
import { makeTypeConstructor } from "../lib/meta/type_constructor.js";
|
||||
import { Bool, Char, Int } from "../lib/primitives/primitive_types.js";
|
||||
import { makeModuleStruct } from "../lib/structures/struct.types.js";
|
||||
import { lsType } from "../lib/structures/type_constructors.types.js";
|
||||
|
||||
|
||||
const symbolPerson = "Person__22a59ca589b4a7efdbe20b52f380e50f";
|
||||
|
||||
const Person = makeTypeConstructor(symbolPerson)(0);
|
||||
|
||||
const fields = [
|
||||
{l: "name", r: lsType(_ => Char)},
|
||||
{l: "age", r: Int},
|
||||
{l: "isMale", r: Bool},
|
||||
];
|
||||
|
||||
const [
|
||||
[, {i: newPerson}],
|
||||
[, {i: getName}],
|
||||
[, {i: getAge}],
|
||||
[, {i: getIsMale}],
|
||||
] = makeModuleStruct(Person)(fields);
|
||||
|
||||
const expectedName = "billy";
|
||||
const expectedAge = 99;
|
||||
const expectedIsMale = true;
|
||||
|
||||
const billy = newPerson(expectedName)(expectedAge)(expectedIsMale);
|
||||
|
||||
const actualName = getName(billy);
|
||||
const actualAge = getAge(billy);
|
||||
const actualIsMale = getIsMale(billy);
|
||||
|
||||
assert.equal(actualName, expectedName);
|
||||
assert.equal(actualAge, expectedAge);
|
||||
assert.equal(actualIsMale, expectedIsMale);
|
||||
Loading…
Add table
Add a link
Reference in a new issue