reorganize directory and file structure
This commit is contained in:
parent
1d826ea8d4
commit
48390b8556
99 changed files with 1155 additions and 1629 deletions
22
lib/structures/dict.js
Normal file
22
lib/structures/dict.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { RBTreeWrapper } from "../util/rbtree_wrapper.js";
|
||||
import { newProduct } from "./product.js";
|
||||
import { newLeft, newRight } from "./sum.js";
|
||||
|
||||
export const emptyDict = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y));
|
||||
|
||||
export const has = dict => key => dict.tree.get(key) === true;
|
||||
export const set = dict => key => value => new RBTreeWrapper(dict.tree.remove(key).insert(key, value));
|
||||
export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key));
|
||||
export const length = dict => dict.tree.length;
|
||||
|
||||
export const first = dict => dict.tree.begin;
|
||||
export const last = dict => dict.tree.end;
|
||||
|
||||
export const read = iter => {
|
||||
if (iter !== undefined && iter.valid) {
|
||||
return newRight(newProduct(newProduct(iter.key)(iter.value))(iter.clone().next()));
|
||||
}
|
||||
else {
|
||||
return newLeft(unit);
|
||||
}
|
||||
};
|
||||
20
lib/structures/dict.types.js
Normal file
20
lib/structures/dict.types.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { makeTypeParser } from "../parser/type_parser.js";
|
||||
import { makeTypeConstructor } from "../meta/type_constructor.js";
|
||||
import { emptyDict, first, has, last, length, read, remove, set } from "./dict.js";
|
||||
|
||||
const dictIterator = makeTypeConstructor('DictIterator__d9d175b6bfd1283f00851a99787d0499')(2);
|
||||
|
||||
const mkType = makeTypeParser({
|
||||
extraInfixOperators: [['|=>|', dictIterator]],
|
||||
});
|
||||
|
||||
export const ModuleDict = [
|
||||
{ i: emptyDict , t: mkType("∀a,b: (a -> a -> Int) -> (a => b)") },
|
||||
{ i: has , t: mkType("∀a,b: (a => b) -> a -> Bool")},
|
||||
{ i: set , t: mkType("∀a,b: (a => b) -> a -> b -> (a => b)")},
|
||||
{ i: remove , t: mkType("∀a,b: (a => b) -> a -> (a => b)")},
|
||||
{ i: length , t: mkType("∀a,b: (a => b) -> Int")},
|
||||
{ i: first , t: mkType("∀a,b: (a => b) -> (a |=>| b)")},
|
||||
{ i: last , t: mkType("∀a,b: (a => b) -> (a |=>| b)")},
|
||||
{ i: read , t: mkType("∀a,b: (a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")},
|
||||
];
|
||||
37
lib/structures/enum.js
Normal file
37
lib/structures/enum.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { capitalizeFirstLetter } from "../util/util.js";
|
||||
import { newProduct as newProduct, getLeft } from "./product.js";
|
||||
import { newLeft, newRight, match } from "./sum.js";
|
||||
|
||||
const eatParameters = (numParams, result) => {
|
||||
if (numParams === 0) {
|
||||
return result;
|
||||
}
|
||||
else return () => eatParameters(numParams-1, result);
|
||||
}
|
||||
|
||||
export const makeMatchFn = variants => {
|
||||
if (variants.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const [_, ...remainingVariants] = variants;
|
||||
return sum => handler => {
|
||||
return match(sum)
|
||||
(leftValue => eatParameters(remainingVariants.length, handler(leftValue)))
|
||||
(rightValue => makeMatchFn(remainingVariants)(rightValue));
|
||||
};
|
||||
};
|
||||
|
||||
export const makeConstructors = variants => {
|
||||
if (variants.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const [variant, ...remainingVariants] = variants;
|
||||
const name = getLeft(variant);
|
||||
const ctorName = `new${capitalizeFirstLetter(name)}`;
|
||||
const constructor = { [ctorName]: val => newLeft(val) }[ctorName];
|
||||
return [
|
||||
constructor,
|
||||
...makeConstructors(remainingVariants).map(ctor =>
|
||||
({[ctor.name]: val => newRight(ctor(val))}[ctor.name])),
|
||||
];
|
||||
}
|
||||
20
lib/structures/enum.types.js
Normal file
20
lib/structures/enum.types.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { Bottom } from "../primitives/primitive_types.js";
|
||||
import { getRight } from "./product.js";
|
||||
import { sumType } from "./type_constructors.js";
|
||||
|
||||
// 'variants' is an array of (name: string, type: Type) pairs.
|
||||
// e.g., the list of variants:
|
||||
// [ { l: "price" , r: Int },
|
||||
// { l: "prices" , r: [Int] },
|
||||
// { l: "not_found", r: Unit } ]
|
||||
// results in the type:
|
||||
// (Int | ([Int] | (Unit | ⊥)))
|
||||
|
||||
export const enumType = variants => {
|
||||
if (variants.length === 0) {
|
||||
return Bottom; // empty enum is equal to Bottom-type (cannot be instantiated)
|
||||
}
|
||||
const [variant, ...rest] = variants;
|
||||
const variantType = getRight(variant);
|
||||
return sumType(() => variantType)(() => enumType(rest));
|
||||
};
|
||||
16
lib/structures/list.js
Normal file
16
lib/structures/list.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// 'normal' implementation
|
||||
export const emptyList = [];
|
||||
// const emptyListType = makeGeneric(a => lsType(() => a));
|
||||
export const get = ls => i => ls[i];
|
||||
export const put = ls => i => elem => ls.with(Number(i), elem);
|
||||
export const push = ls => elem => ls.concat([elem]);
|
||||
export const pop = ls => ls.pop();
|
||||
export const map = ls => fn => ls.map(elem => fn(elem));
|
||||
export const length = ls => ls.length;
|
||||
export const fold = ls => callback => initial => {
|
||||
let acc = initial;
|
||||
for (let i=0; i<ls.length; i++) {
|
||||
acc = callback(acc)(ls[i]);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
15
lib/structures/list.types.js
Normal file
15
lib/structures/list.types.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { getDefaultTypeParser }from "../parser/type_parser.js";
|
||||
import { emptyList, fold, get, length, map, pop, push, put } from "./list.js";
|
||||
|
||||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleList = [
|
||||
{ i: emptyList, t: mkType("∀a: [a]")},
|
||||
{ i: get , t: mkType("∀a: [a] -> Int -> a")},
|
||||
{ i: put , t: mkType("∀a: [a] -> Int -> a -> [a]")},
|
||||
{ i: push , t: mkType("∀a: [a] -> a -> [a]")},
|
||||
{ i: pop , t: mkType("∀a: [a] -> a")},
|
||||
{ i: map , t: mkType("∀a: [a] -> (a -> b) -> [b]")},
|
||||
{ i: length , t: mkType("∀a: [a] -> Int")},
|
||||
{ i: fold , t: mkType("∀a: [a] -> (b -> a -> b) -> b -> b")},
|
||||
];
|
||||
9
lib/structures/product.js
Normal file
9
lib/structures/product.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Product-type (also called: pair, tuple)
|
||||
|
||||
// A Product-type always has only two fields, called "left" and "right".
|
||||
// Product-types of more fields (called Structs) can be constructed by nesting Product-types.
|
||||
|
||||
// In JS, all products are encoded in the same way:
|
||||
export const newProduct = l => r => ({l, r});
|
||||
export const getLeft = product => product.l;
|
||||
export const getRight = product => product.r;
|
||||
10
lib/structures/product.types.js
Normal file
10
lib/structures/product.types.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { getDefaultTypeParser } from "../parser/type_parser.js";
|
||||
import { newProduct, getLeft, getRight } from "./product.js";
|
||||
|
||||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleProduct = [
|
||||
{ i: newProduct, t: mkType("∀a,b: a -> b -> (a * b)") },
|
||||
{ i: getLeft , t: mkType("∀a,b: (a * b) -> a" ) },
|
||||
{ i: getRight , t: mkType("∀a,b: (a * b) -> b" ) },
|
||||
];
|
||||
29
lib/structures/set.js
Normal file
29
lib/structures/set.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { newRight } from "./sum.js";
|
||||
import { newProduct } from "./product.js";
|
||||
import { unit } from "../primitives/unit.js";
|
||||
import { RBTreeWrapper } from "../util/rbtree_wrapper.js";
|
||||
|
||||
// (a -> a -> Int) -> Set(a)
|
||||
export const emptySet = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y));
|
||||
|
||||
export const has = set => key => set.tree.get(key) === true;
|
||||
export const add = set => key => set.tree.get(key) === true ? set : new RBTreeWrapper(set.tree.insert(key, true));
|
||||
export const remove = set => key => new RBTreeWrapper(set.tree.remove(key));
|
||||
export const length = set => set.tree.length;
|
||||
|
||||
export const first = set => set.tree.begin;
|
||||
export const last = set => set.tree.end;
|
||||
|
||||
// test if iterator is 'done', and if not, get element and advance iterator.
|
||||
export const read = iter => {
|
||||
if (iter !== undefined && iter.valid) {
|
||||
return newRight(newProduct(iter.key)(iter.clone().next()));
|
||||
}
|
||||
else {
|
||||
return newLeft(unit);
|
||||
}
|
||||
};
|
||||
|
||||
export const forEach = set => fn => {
|
||||
set.tree.forEach(key => { fn(key); });
|
||||
};
|
||||
20
lib/structures/set.types.js
Normal file
20
lib/structures/set.types.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { makeTypeParser } from "../parser/type_parser.js";
|
||||
import { makeTypeConstructor } from "../meta/type_constructor.js";
|
||||
import { emptySet, has, add, remove, length, first, read, last } from "./set.js";
|
||||
|
||||
const setIterator = makeTypeConstructor('SetIterator__f6b0ddd78ed41c58e5a442f2681da011')(1);
|
||||
|
||||
const mkType = makeTypeParser({
|
||||
extraBracketOperators: [['<', ['>', setIterator]]],
|
||||
});
|
||||
|
||||
export const ModuleSet = [
|
||||
{ i: emptySet , t: mkType("∀a: (a -> a -> Int) -> {a}") },
|
||||
{ i: has , t: mkType("∀a: {a} -> a -> Bool")},
|
||||
{ i: add , t: mkType("∀a: {a} -> a -> {a}")},
|
||||
{ i: remove , t: mkType("∀a: {a} -> a -> {a}")},
|
||||
{ i: length , t: mkType("∀a: {a} -> Int")},
|
||||
{ i: first , t: mkType("∀a: {a} -> <a>")},
|
||||
{ i: last , t: mkType("∀a: {a} -> <a>")},
|
||||
{ i: read , t: mkType("∀a: <a> -> (Unit + (a * <a>))")},
|
||||
];
|
||||
33
lib/structures/struct.js
Normal file
33
lib/structures/struct.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
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) {
|
||||
const result = ret(unit);
|
||||
return result;
|
||||
}
|
||||
return nextParam => {
|
||||
const wrappedName = 'wrapped_' + ret.name;
|
||||
const newRet = {
|
||||
[wrappedName]: inner => newProduct(nextParam)(ret(inner)),
|
||||
}[wrappedName];
|
||||
return internal(nParams-1, newRet);
|
||||
}
|
||||
};
|
||||
const id = x => x;
|
||||
return internal(nParams, id);
|
||||
};
|
||||
|
||||
export const makeGetters = fieldNames => {
|
||||
if (fieldNames.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const [fieldName, ...rest] = fieldNames;
|
||||
const getterName = `get${capitalizeFirstLetter(fieldName)}`;
|
||||
return [
|
||||
{ [getterName]: obj => getLeft(obj) }[getterName],
|
||||
...makeGetters(rest).map(getter => ({[getter.name]: obj => getter(getRight(obj))}[getter.name])),
|
||||
];
|
||||
};
|
||||
61
lib/structures/struct.types.js
Normal file
61
lib/structures/struct.types.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
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.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 = fieldTypes => {
|
||||
if (fieldTypes.length === 0) {
|
||||
return Unit;
|
||||
}
|
||||
const [fieldType, ...rest] = fieldTypes;
|
||||
return prodType(_ => fieldType)(_ => structType(rest));
|
||||
};
|
||||
|
||||
export const makeConstructorType = fieldTypes => {
|
||||
if (fieldTypes.length === 0) {
|
||||
return structType(fieldTypes);
|
||||
}
|
||||
const [fieldType, ...rest] = fieldTypes;
|
||||
return fnType(_ => fieldType)(_ => makeConstructorType(rest));
|
||||
};
|
||||
|
||||
export const makeGettersTypes = fieldTypes => {
|
||||
const type = structType(fieldTypes);
|
||||
return fieldTypes.map(fieldType => {
|
||||
return fnType(_ => type)(_ => fieldType);
|
||||
});
|
||||
};
|
||||
|
||||
export const makeModuleStruct = fields => {
|
||||
const fieldNames = map(fields)(getLeft);
|
||||
const fieldTypes = map(fields)(getRight);
|
||||
const type = structType(fieldTypes);
|
||||
const ctor = makeConstructor(fields.length);
|
||||
const ctorType = makeConstructorType(fieldTypes);
|
||||
const getterTypes = makeGettersTypes(fieldTypes);
|
||||
const getters = makeGetters(fieldNames);
|
||||
const module = [
|
||||
{i: type, t: Type},
|
||||
{i: ctor, t: ctorType},
|
||||
...zip(getters, getterTypes)
|
||||
.map(([getter, getterType]) => newDynamic(getter)(getterType)),
|
||||
];
|
||||
return module;
|
||||
};
|
||||
|
||||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleStruct = [
|
||||
{i: structType, t: mkType("[String*Type] -> Type")},
|
||||
{i: makeModuleStruct, t: mkType("[String*Type] -> [Dynamic]")},
|
||||
];
|
||||
11
lib/structures/sum.js
Normal file
11
lib/structures/sum.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Sum-type (also called: tagged union, disjoint union, variant type)
|
||||
// A Sum-type always has only two variants, called "left" and "right".
|
||||
// Sum-types of more variants (called Enums) can be constructed by nesting Sum-types.
|
||||
|
||||
export const newLeft = left => ({t: "L", v: left });
|
||||
export const newRight = right => ({t: "R", v: right});
|
||||
|
||||
export const match = sum => leftHandler => rightHandler =>
|
||||
sum.t === "L"
|
||||
? leftHandler(sum.v)
|
||||
: rightHandler(sum.v);
|
||||
10
lib/structures/sum.types.js
Normal file
10
lib/structures/sum.types.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { getDefaultTypeParser }from "../parser/type_parser.js";
|
||||
import { match, newLeft, newRight } from "./sum.js";
|
||||
|
||||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleSum = [
|
||||
{ i: newLeft , t: mkType("∀a,b: a -> (a + b)") },
|
||||
{ i: newRight , t: mkType("∀a,b: b -> (a + b)") },
|
||||
{ i: match , t: mkType("∀a,b,c: (a + b) -> (a -> c) -> (b -> c) -> c") },
|
||||
];
|
||||
17
lib/structures/type_constructors.js
Normal file
17
lib/structures/type_constructors.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// to break up dependency cycles, type constructors are defined in their own JS module
|
||||
|
||||
import { makeTypeConstructor } from "../meta/type_constructor.js";
|
||||
|
||||
export const symbolFunction = "Function__c2433e31fa574a2cb3b6b5d62ac9d4b2";
|
||||
export const symbolSum = "Sum__89b731efa6344ea0b6a8663a45cf3ea8";
|
||||
export const symbolProduct = "Product__89351ecdedfb4b05b2a5a6cc0c383e12";
|
||||
export const symbolList = "List__daa8de8a9047435e96034ec64f2da3a1";
|
||||
export const symbolSet = "Set__8fef2c1873df4327ac31bd61d2ecf7e0";
|
||||
export const symbolDict = "Dict__d7158547322549ac9f7f8176aec123dd";
|
||||
|
||||
export const fnType = makeTypeConstructor(symbolFunction)(2);
|
||||
export const sumType = makeTypeConstructor(symbolSum)(2);
|
||||
export const prodType = makeTypeConstructor(symbolProduct)(2);
|
||||
export const lsType = makeTypeConstructor(symbolList)(1);
|
||||
export const setType = makeTypeConstructor(symbolSet)(1);
|
||||
export const dictType = makeTypeConstructor(symbolDict)(2);
|
||||
23
lib/structures/type_constructors.types.js
Normal file
23
lib/structures/type_constructors.types.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { getDefaultTypeParser } from "../parser/type_parser.js";
|
||||
import { SymbolT } from "../primitives/primitive_types.js";
|
||||
import { dictType, fnType, lsType, prodType, setType, sumType, symbolDict, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSum } from "./type_constructors.js";
|
||||
|
||||
const mkType = getDefaultTypeParser();
|
||||
|
||||
export const ModuleStructuralSymbols = [
|
||||
{ i: symbolSet , t: SymbolT },
|
||||
{ i: symbolList , t: SymbolT },
|
||||
{ i: symbolProduct , t: SymbolT },
|
||||
{ i: symbolSum , t: SymbolT },
|
||||
{ i: symbolDict , t: SymbolT },
|
||||
{ i: symbolFunction , t: SymbolT },
|
||||
];
|
||||
|
||||
export const ModuleTypeConstructors = [
|
||||
{ i: setType , t: mkType("Type -> Type") },
|
||||
{ i: lsType , t: mkType("Type -> Type") },
|
||||
{ i: prodType , t: mkType("Type -> Type -> Type") },
|
||||
{ i: sumType , t: mkType("Type -> Type -> Type") },
|
||||
{ i: dictType , t: mkType("Type -> Type -> Type") },
|
||||
{ i: fnType , t: mkType("Type -> Type -> Type") },
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue