wip
This commit is contained in:
parent
afd78c3b3e
commit
29d20b2273
25 changed files with 369 additions and 469 deletions
51
structures/function.js
Normal file
51
structures/function.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { DefaultMap } from "../util.js";
|
||||
|
||||
const symbolFunction = Symbol('Function');
|
||||
|
||||
// The registry ensures that we never accidentally create more than one JS object for the same function type.
|
||||
// It is a cheap workaround for JS lacking customizable hash-functions and equality-testing-functions.
|
||||
// This same pattern is repeated throughout the code for all non-nullary type constructors (list, sum, product, ...)
|
||||
const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({
|
||||
symbol: symbolFunction,
|
||||
params: [inType, outType],
|
||||
})));
|
||||
|
||||
// type constructor for function types
|
||||
export const fnType = inType => outType => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
||||
|
||||
|
||||
// Wrapper around function below.
|
||||
export const typedFnType = (instance, callback) => {
|
||||
const [t, typesOfFns] = typedFnType2(callback);
|
||||
const res = [
|
||||
{ i: instance, t },
|
||||
...typesOfFns,
|
||||
];
|
||||
return res;
|
||||
};
|
||||
// Create a function type, and also create Type-links for the function type (being typed by Function) and for all the nested function types. Saves a lot of code writing.
|
||||
export const typedFnType2 = callback => {
|
||||
const fnTs = [];
|
||||
const wrappedFnType = ({ in: inType, out: outType }) => {
|
||||
const fnT = fnType({ in: inType, out: outType });
|
||||
fnTs.push(fnT);
|
||||
return fnT;
|
||||
};
|
||||
const t = callback(wrappedFnType); // force evaluation
|
||||
return [
|
||||
t,
|
||||
fnTs.map(fnT => ({ i: fnT, t: Function })),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
export const ModuleFunction = {l:[
|
||||
// binary type constructor: Type -> Type -> Type
|
||||
...typedFnType(fnType, fnType => fnType
|
||||
/* in */ (Type)
|
||||
/* out */ (fnType
|
||||
/* in */ (Type)
|
||||
/* out */ (Type)
|
||||
)
|
||||
),
|
||||
]};
|
||||
|
|
@ -1,16 +1,51 @@
|
|||
import { lsType } from "./list_common.js";
|
||||
import { fnType } from "../metacircular.js";
|
||||
import {Type, Function} from "../metacircular.js";
|
||||
import { makeListModule } from "./list_common.js";
|
||||
import { Module } from "./list_types/module.js";
|
||||
import { typedFnType } from "./function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { Int } from "../primitives/symbols.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
|
||||
const Type_to_Type = fnType({in: Type, out: Type});
|
||||
const Type_to_Module = fnType({in: Type, out: Module});
|
||||
const symbolList = Symbol('List');
|
||||
|
||||
const listTypeRegistry = new DefaultMap(elementType => ({
|
||||
symbol: symbolList,
|
||||
params: [elementType],
|
||||
}));
|
||||
|
||||
// type constructor
|
||||
export const lsType = elementType => listTypeRegistry.getdefault(elementType, true);
|
||||
|
||||
// 'normal' implementation
|
||||
const emptyList = {l:[]};
|
||||
const get = ls => i => ls.l[i];
|
||||
const put = ls => i => elem => ({l: ls.l.with(Number(i), elem)});
|
||||
// const push = ls => elem => ({l:ls.l.concat([elem])});
|
||||
|
||||
export const ModuleList = {l:[
|
||||
{i: lsType , t: Type_to_Type},
|
||||
{i: Type_to_Type , t: Function},
|
||||
// Type -> Type
|
||||
...typedFnType(lsType, fnType => fnType
|
||||
/* in */ (Type)
|
||||
/* out */ (Type)
|
||||
),
|
||||
|
||||
{i: makeListModule, t: Type_to_Module},
|
||||
{i: Type_to_Module, t: Function},
|
||||
// [a]
|
||||
{i: emptyList, t: makeGeneric(a => lsType(a))},
|
||||
|
||||
// [a] -> Int -> a
|
||||
...typedFnType(get, fnType => makeGeneric(a => fnType
|
||||
/* in */ (lsType(a))
|
||||
/* out */ (fnType
|
||||
/* in */ (Int)
|
||||
/* out */ (a)
|
||||
))),
|
||||
|
||||
// [a] -> Int -> a -> [a]
|
||||
...typedFnType(put, fnType => makeGeneric(a => fnType
|
||||
/* in */ (lsType(a))
|
||||
/* out */ (fnType
|
||||
/* in */ (Int)
|
||||
/* out */ (fnType
|
||||
/* in */ (a)
|
||||
/* out */ (lsType(a))
|
||||
)
|
||||
))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
import { fnType } from "../metacircular.js";
|
||||
import {Type, Function} from "../metacircular.js";
|
||||
import {Int, Byte} from "../primitives/symbols.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
|
||||
const listTypeRegistry = new DefaultMap(elementType => ({ listOf: elementType }));
|
||||
|
||||
// type constructor
|
||||
export const lsType = elementType => listTypeRegistry.getdefault(elementType, true);
|
||||
|
||||
// 'normal' implementation
|
||||
const emptyList = {l:[]};
|
||||
const get = ls => i => ls.l[i];
|
||||
const put = ls => i => elem => ({l: ls.l.with(Number(i), elem)});
|
||||
// const push = ls => elem => ({l:ls.l.concat([elem])});
|
||||
|
||||
const byteListImpl = {
|
||||
// specialization
|
||||
emptyList: new Uint8Array(),
|
||||
get: ls => i => ls[i],
|
||||
put: ls => i => elem => {
|
||||
res = new Uint8Array(ls); // creates copy
|
||||
res[i] = elem;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export const makeListModule = elementType => {
|
||||
// List<elementType> type depends on elementType
|
||||
// generating it another time, will give the same type (structurally equivalent):
|
||||
const ListOfElement = lsType(elementType);
|
||||
|
||||
const getFnType1 = fnType({in: Int , out: elementType});
|
||||
const getFnType = fnType({in: ListOfElement, out: getFnType1});
|
||||
|
||||
const putFnType2 = fnType({in: elementType , out: ListOfElement});
|
||||
const putFnType1 = fnType({in: Int , out: putFnType2});
|
||||
const putFnType = fnType({in: ListOfElement, out: putFnType1});
|
||||
|
||||
// const pushFnType1 = fnType({in: elementType , out: ListOfElement});
|
||||
// const pushFnType = fnType({in: ListOfElement, out: pushFnType1});
|
||||
|
||||
const common = [
|
||||
{i: ListOfElement, t: Type},
|
||||
|
||||
{i: getFnType , t: Function},
|
||||
{i: getFnType1 , t: Function},
|
||||
|
||||
{i: putFnType , t: Function},
|
||||
{i: putFnType1, t: Function},
|
||||
{i: putFnType2, t: Function},
|
||||
|
||||
// {i: pushFnType , t: Function},
|
||||
// {i: pushFnType1, t: Function},
|
||||
];
|
||||
|
||||
if (elementType === Byte) {
|
||||
// specialization: use Uint8Array instead of JS array
|
||||
return {l:[
|
||||
...common,
|
||||
{i: byteListImpl.emptyList , t: ListOfElement},
|
||||
{i: byteListImpl.get , t: getFnType},
|
||||
{i: byteListImpl.put , t: putFnType},
|
||||
]};
|
||||
}
|
||||
else {
|
||||
return {l:[
|
||||
...common,
|
||||
{i: emptyList , t: ListOfElement},
|
||||
{i: get , t: getFnType},
|
||||
{i: put , t: putFnType},
|
||||
// {i: push , t: pushFnType},
|
||||
]};
|
||||
}
|
||||
};
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { makeListModule } from "../list_common.js";
|
||||
import { makeListModule } from "../list.js";
|
||||
import { Typed } from "../../typed.js";
|
||||
import { lsType } from "../list_common.js";
|
||||
import { lsType } from "../list.js";
|
||||
|
||||
// just an alias
|
||||
export const Module = lsType(Typed); // a Module is a list of Typeds
|
||||
|
||||
export const ModuleModule = makeListModule(Typed); // the module containing operations on Module
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Char } from "../../primitives/symbols.js";
|
||||
import { lsType } from "../list_common.js";
|
||||
import { makeListModule } from "../list_common.js";
|
||||
import { lsType } from "../list.js";
|
||||
import { makeListModule } from "../list.js";
|
||||
|
||||
// just an alias
|
||||
export const String = lsType(Char);
|
||||
|
||||
export const ModuleString = makeListModule(Char);
|
||||
|
|
@ -1,37 +1,51 @@
|
|||
import { fnType } from "../metacircular.js";
|
||||
import { Function, Type } from "../metacircular.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { typedFnType } from "./function.js";
|
||||
|
||||
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ operator: "product", leftType, rightType })));
|
||||
const symbolProduct = Symbol("Product");
|
||||
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolProduct,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
|
||||
// type constructor
|
||||
export const prodType = (leftType, rightType) => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
export const prodType = leftType => rightType => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
|
||||
// In JS, all products are encoded in the same way:
|
||||
const constructor = left => right => ({left, right});
|
||||
const getLeft = product => product.left;
|
||||
const getRight = product => product.right;
|
||||
|
||||
// Given two types A and B, create the type (A × B).
|
||||
export const makeProductType = (leftType, rightType) => {
|
||||
const pType = prodType(leftType, rightType);
|
||||
export const ModuleProduct = {l: [
|
||||
// binary type constructor
|
||||
// Type -> Type -> Type
|
||||
...typedFnType(prodType, fnType => fnType
|
||||
(Type)
|
||||
(fnType
|
||||
(Type)
|
||||
(Type)
|
||||
)
|
||||
),
|
||||
|
||||
const leftFnType = fnType({in: pType, out: leftType});
|
||||
const rightFnType = fnType({in: pType, out: rightType});
|
||||
// a -> b -> (a, b)
|
||||
...typedFnType(constructor, fnType => makeGeneric((a, b) => fnType
|
||||
(a)
|
||||
(fnType
|
||||
(b)
|
||||
(prodType(a)(b))
|
||||
)
|
||||
)),
|
||||
|
||||
const constructorBoundType = fnType({in: rightType, out: pType});
|
||||
const constructorType = fnType({in: leftType , out: constructorBoundType});
|
||||
// (a, b) -> a
|
||||
...typedFnType(getLeft, fnType => makeGeneric((a, b) => fnType
|
||||
(prodType(a)(b))
|
||||
(a)
|
||||
)),
|
||||
|
||||
return {l:[
|
||||
{i: pType, t: Type},
|
||||
|
||||
{i: getLeft , t: leftFnType},
|
||||
{i: getRight , t: rightFnType},
|
||||
{i: leftFnType , t: Function},
|
||||
{i: rightFnType, t: Function},
|
||||
|
||||
{i: constructor , t: constructorType},
|
||||
{i: constructorType , t: Function},
|
||||
{i: constructorBoundType, t: Function},
|
||||
]};
|
||||
};
|
||||
// (a, b) -> b
|
||||
...typedFnType(getRight, fnType => makeGeneric((a, b) => fnType
|
||||
(prodType(a)(b))
|
||||
(b)
|
||||
)),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,53 +1,60 @@
|
|||
import { prodType } from "./product.js";
|
||||
import { fnType } from "../metacircular.js";
|
||||
import { Function, Type } from "../metacircular.js";
|
||||
import { Module } from "./list_types/module.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { typedFnType } from "./function.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
|
||||
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ operator: "sum", leftType, rightType })));
|
||||
const symbolSum = Symbol("Sum");
|
||||
|
||||
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolSum,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
|
||||
// type constructor
|
||||
export const sumType = (leftType, rightType) => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
export const sumType = leftType => rightType => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
|
||||
const constructorLeft = left => ({variant: "L", value: left });
|
||||
const constructorRight = right => ({variant: "R", value: right});
|
||||
|
||||
// (<uuid>, product(double, double)): product(int, type)
|
||||
|
||||
// signature:
|
||||
// sum-type -> (leftType -> resultType, rightType -> resultType) -> resultType
|
||||
const match = sum => handlers => sum.variant === "L"
|
||||
? handlers.left(sum.value)
|
||||
: handlers.right(sum.value);
|
||||
|
||||
// Given two types A and B, create the type (A + B).
|
||||
export const makeSumType = (leftType, rightType) => {
|
||||
const sType = sumType(leftType, rightType);
|
||||
export const ModuleSum = {l:[
|
||||
// binary type constructor
|
||||
// Type -> Type -> Type
|
||||
...typedFnType(sumType, fnType => fnType
|
||||
(Type)
|
||||
(fnType
|
||||
(Type)
|
||||
(Type)
|
||||
),
|
||||
),
|
||||
|
||||
const constructorLeftType = fnType({in: leftType , out: sType});
|
||||
const constructorRightType = fnType({in: rightType, out: sType});
|
||||
// a -> a | b
|
||||
...typedFnType(constructorLeft, fnType => makeGeneric((a, b) => fnType
|
||||
(a)
|
||||
(sumType(a)(b))
|
||||
)),
|
||||
|
||||
// For each possible return type, the match function has a different signature.
|
||||
// We thus define a function that creates a properly typed match function.
|
||||
const makeMatchFn = returnType => {
|
||||
const handlersType = prodType(
|
||||
fnType({in: leftType , out: returnType}), // handler function for left variant
|
||||
fnType({in: rightType, out: returnType}), // handler function for right variant
|
||||
);
|
||||
const matchFnType = fnType({in: sType, out: fnType({in: handlersType, out: returnType})});
|
||||
return {l:[
|
||||
{i: match , t: matchFnType},
|
||||
{i: matchFnType, t: Function},
|
||||
]};
|
||||
};
|
||||
// b -> a | b
|
||||
...typedFnType(constructorRight, fnType => makeGeneric((a, b) => fnType
|
||||
(b)
|
||||
(sumType(a)(b))
|
||||
)),
|
||||
|
||||
return {l:[
|
||||
{i: sType , t: Type},
|
||||
{i: constructorLeft , t: constructorLeftType},
|
||||
{i: constructorRight , t: constructorRightType},
|
||||
{i: constructorLeftType , t: Function},
|
||||
{i: constructorRightType, t: Function},
|
||||
|
||||
{i: makeMatchFn, t: fnType({in: Type, out: Module})},
|
||||
]};
|
||||
};
|
||||
// a | b -> (a -> c, b-> c) -> c
|
||||
...typedFnType(match, fnType => makeGeneric((a, b, c) => fnType
|
||||
(sumType(a)(b))
|
||||
(fnType
|
||||
(prodType
|
||||
(fnType(a)(c))
|
||||
(fnType(b)(c))
|
||||
)
|
||||
(c)
|
||||
)
|
||||
)),
|
||||
]};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue