refactor code: move everything from type_registry to "most appropriate" modules
This commit is contained in:
parent
4ca60784aa
commit
5283be608b
22 changed files with 160 additions and 164 deletions
|
|
@ -1,6 +1,21 @@
|
||||||
import { fnType, lsType } from "../type_registry.js";
|
import { lsType } from "../structures/list_common.js";
|
||||||
|
import { fnType } from "../metacircular.js";
|
||||||
import { deepEqual, pretty } from "../util.js";
|
import { deepEqual, pretty } from "../util.js";
|
||||||
|
|
||||||
|
const genericTypeRegistry = new DefaultMap(underlyingType => ({generic: underlyingType}));
|
||||||
|
|
||||||
|
// type constructor for generic kinds,
|
||||||
|
// for instance:
|
||||||
|
// a -> a -> Bool
|
||||||
|
// is typed by
|
||||||
|
// genericType(Function)
|
||||||
|
export const genericType = underlyingType => genericTypeRegistry.getdefault(underlyingType, true);
|
||||||
|
|
||||||
|
// constructor for generic types
|
||||||
|
// for instance, the type:
|
||||||
|
// a -> a -> Bool
|
||||||
|
// is created by
|
||||||
|
// makeGeneric(a => fnType({in: a, out: fnType({in: a, out: Bool})}))
|
||||||
export const makeGeneric = callback => {
|
export const makeGeneric = callback => {
|
||||||
// type variables to make available:
|
// type variables to make available:
|
||||||
const a = Symbol('a');
|
const a = Symbol('a');
|
||||||
|
|
@ -32,14 +47,11 @@ const occurring = (type, typeVars) => {
|
||||||
return new Set();
|
return new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge_int(1, 2) => conflict(1,2)
|
// Currently very ad-hoc.
|
||||||
// merge_list_of_int([1], [2]) => [conflict(1,2)]
|
|
||||||
|
|
||||||
// merge {i: [1], t: List_of_Int} ->
|
// Thanks to Hans for pointing out that this algorithm exactly like "Unification" in Prolog (hence the function name):
|
||||||
|
|
||||||
// Thanks to Hans for pointing out that this algorithm exactly like "Unification" in Prolog:
|
|
||||||
// https://www.dai.ed.ac.uk/groups/ssp/bookpages/quickprolog/node12.html
|
// https://www.dai.ed.ac.uk/groups/ssp/bookpages/quickprolog/node12.html
|
||||||
export const matchGeneric = (
|
export const unify = (
|
||||||
{typeVars: formalTypeVars, type: formalType},
|
{typeVars: formalTypeVars, type: formalType},
|
||||||
{typeVars: actualTypeVars, type: actualType},
|
{typeVars: actualTypeVars, type: actualType},
|
||||||
) => {
|
) => {
|
||||||
|
|
@ -71,8 +83,8 @@ export const matchGeneric = (
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// both are function type
|
// both are function type
|
||||||
const inType = matchGeneric({typeVars: formalTypeVars, type: formalType.in}, {typeVars: actualTypeVars, type: actualType.in});
|
const inType = unify({typeVars: formalTypeVars, type: formalType.in}, {typeVars: actualTypeVars, type: actualType.in});
|
||||||
const outType = matchGeneric({typeVars: formalTypeVars, type: formalType.out}, {typeVars: actualTypeVars, type: actualType.out});
|
const outType = unify({typeVars: formalTypeVars, type: formalType.out}, {typeVars: actualTypeVars, type: actualType.out});
|
||||||
// check for conflicts between 'in' and 'out' subsitutions
|
// check for conflicts between 'in' and 'out' subsitutions
|
||||||
for (const [typeVar, actual] of inType.substitutions) {
|
for (const [typeVar, actual] of inType.substitutions) {
|
||||||
if (outType.substitutions.has(typeVar)) {
|
if (outType.substitutions.has(typeVar)) {
|
||||||
|
|
@ -104,7 +116,7 @@ export const matchGeneric = (
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// both are list type
|
// both are list type
|
||||||
const elementType = matchGeneric(
|
const elementType = unify(
|
||||||
{typeVars: formalTypeVars, type: formalType.listOf},
|
{typeVars: formalTypeVars, type: formalType.listOf},
|
||||||
{typeVars: actualTypeVars, type: actualType.listOf});
|
{typeVars: actualTypeVars, type: actualType.listOf});
|
||||||
return {
|
return {
|
||||||
|
|
@ -116,12 +128,16 @@ export const matchGeneric = (
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (formalType.numDict !== undefined) {
|
||||||
|
|
||||||
|
}
|
||||||
throw new Error("i don't know what to do :(")
|
throw new Error("i don't know what to do :(")
|
||||||
};
|
};
|
||||||
|
|
||||||
export const matchConcrete = ({typeVars, type: formalType}, actualType) => {
|
// export const matchConcrete = ({typeVars, type: formalType}, actualType) => {
|
||||||
return matchGeneric({typeVars, type: formalType}, {typeVars: new Set(), type: actualType});
|
// return unify({typeVars, type: formalType}, {typeVars: new Set(), type: actualType});
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const substitute = (type, substitutions) => {
|
export const substitute = (type, substitutions) => {
|
||||||
if (substitutions.has(type)) {
|
if (substitutions.has(type)) {
|
||||||
|
|
@ -142,7 +158,7 @@ export const substitute = (type, substitutions) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const assign = (genFnType, paramType) => {
|
export const assign = (genFnType, paramType) => {
|
||||||
const matchedInType = matchGeneric({
|
const matchedInType = unify({
|
||||||
typeVars: genFnType.typeVars,
|
typeVars: genFnType.typeVars,
|
||||||
type: genFnType.type.in,
|
type: genFnType.type.in,
|
||||||
}, paramType);
|
}, paramType);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
import { Bool, Int } from "../primitives/symbols.js";
|
import { Bool, Int } from "../primitives/symbols.js";
|
||||||
import { fnType, lsType } from "../type_registry.js";
|
import { lsType } from "../structures/list_common.js";
|
||||||
import { assign, makeGeneric, matchConcrete, matchGeneric } from "./generics.js";
|
import { fnType } from "../metacircular.js";
|
||||||
|
import { assign, makeGeneric, unify } from "./generics.js";
|
||||||
|
|
||||||
// a -> Int
|
// a -> Int
|
||||||
const a_to_Int = makeGeneric(a => fnType({in: a, out: Int}));
|
const a_to_Int = makeGeneric(a => fnType({in: a, out: Int}));
|
||||||
// Bool -> Int
|
// Bool -> Int
|
||||||
const Bool_to_Int = fnType({in: lsType(Bool), out: Int});
|
const Bool_to_Int = makeGeneric(() => fnType({in: lsType(Bool), out: Int}));
|
||||||
// should be: Bool -> Int
|
// should be: Bool -> Int
|
||||||
console.log(matchConcrete(a_to_Int, Bool_to_Int));
|
console.log(unify(a_to_Int, Bool_to_Int));
|
||||||
|
|
||||||
// (a -> a) -> b
|
// (a -> a) -> b
|
||||||
const fnType2 = makeGeneric((a,b) => fnType({in: fnType({in: a, out: a}), out: b}));
|
const fnType2 = makeGeneric((a,b) => fnType({in: fnType({in: a, out: a}), out: b}));
|
||||||
// (Bool -> Bool) -> a
|
// (Bool -> Bool) -> a
|
||||||
const fnType3 = makeGeneric(a => fnType({in: fnType({in: Bool, out: Bool}), out: a}));
|
const fnType3 = makeGeneric(a => fnType({in: fnType({in: Bool, out: Bool}), out: a}));
|
||||||
// should be: (Bool -> Bool) -> a
|
// should be: (Bool -> Bool) -> a
|
||||||
console.log(matchGeneric(fnType2, fnType3));
|
console.log(unify(fnType2, fnType3));
|
||||||
|
|
||||||
// (a -> b) -> [a] -> [b]
|
// (a -> b) -> [a] -> [b]
|
||||||
const mapFnType = makeGeneric((a,b) =>
|
const mapFnType = makeGeneric((a,b) =>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { fnType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import {Function} from "../metacircular.js";
|
import {Function} from "../metacircular.js";
|
||||||
|
|
||||||
// import {Typed} from "../typed.js";
|
// import {Typed} from "../typed.js";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { Double } from "../primitives/symbols.js";
|
import { Double } from "../primitives/symbols.js";
|
||||||
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
||||||
import { makeProductType } from "../structures/product.js";
|
import { makeProductType } from "../structures/product.js";
|
||||||
import { prodType, typedFnType } from "../type_registry.js";
|
import { typedFnType } from "../metacircular.js";
|
||||||
|
import { prodType } from "../structures/product.js";
|
||||||
|
|
||||||
const PointCartesian2D = nominalType(
|
const PointCartesian2D = nominalType(
|
||||||
"PointCartesian2D")
|
"PointCartesian2D")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import {Function, getIn, getOut} from "../metacircular.js";
|
||||||
import {Module} from "../structures/list_types/module.js";
|
import {Module} from "../structures/list_types/module.js";
|
||||||
import { deepEqual } from "../util.js";
|
import { deepEqual } from "../util.js";
|
||||||
import { Typed } from "../typed.js";
|
import { Typed } from "../typed.js";
|
||||||
import { fnType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
|
|
||||||
// import {Num, NumDict, getType, getMul} from "../typeclasses/num.js";
|
// import {Num, NumDict, getType, getMul} from "../typeclasses/num.js";
|
||||||
|
|
||||||
|
|
|
||||||
4
main.js
4
main.js
|
|
@ -13,7 +13,9 @@ import {Int, Bool, Double, Byte} from "./primitives/symbols.js";
|
||||||
import { makeListModule } from "./structures/list_common.js";
|
import { makeListModule } from "./structures/list_common.js";
|
||||||
import { makeProductType } from "./structures/product.js";
|
import { makeProductType } from "./structures/product.js";
|
||||||
import { makeSumType } from "./structures/sum.js";
|
import { makeSumType } from "./structures/sum.js";
|
||||||
import { lsType, prodType, sumType } from "./type_registry.js";
|
import { sumType } from "./structures/sum.js";
|
||||||
|
import { prodType } from "./structures/product.js";
|
||||||
|
import { lsType } from "./structures/list_common.js";
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
constructor(mod) {
|
constructor(mod) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
import { fnType } from "./type_registry.js";
|
import { DefaultMap } from "./util.js";
|
||||||
|
|
||||||
|
// 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 => ({ in: inType, out: outType })));
|
||||||
|
|
||||||
|
// type constructor for function types
|
||||||
|
export const fnType = ({ in: inType, out: outType }) => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
||||||
|
|
||||||
export const Type = Symbol('Type');
|
export const Type = Symbol('Type');
|
||||||
export const Function = Symbol('Function');
|
export const Function = Symbol('Function');
|
||||||
|
|
@ -29,3 +37,30 @@ export const ModuleMetaCircular = {l:[
|
||||||
{i: getIn , t: fnType({in: Function, out: Type})},
|
{i: getIn , t: fnType({in: Function, out: Type})},
|
||||||
{i: getOut, t: fnType({in: Function, out: Type})},
|
{i: getOut, t: fnType({in: Function, out: Type})},
|
||||||
]};
|
]};
|
||||||
|
|
||||||
|
|
||||||
|
// 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 }) => {
|
||||||
|
console.log('wrappedFnType called');
|
||||||
|
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 })),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { fnType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import {Type, Function} from "../metacircular.js";
|
import {Type, Function} from "../metacircular.js";
|
||||||
import {Bool} from "./symbols.js";
|
import {Bool} from "./symbols.js";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { fnType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import {Type, Function} from "../metacircular.js";
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
|
||||||
import {Bool, Double} from "./symbols.js";
|
import {Bool, Double} from "./symbols.js";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { fnType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import {Type, Function} from "../metacircular.js";
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
|
||||||
import {Bool, Int} from "./symbols.js";
|
import {Bool, Int} from "./symbols.js";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { fnType, lsType } from "../type_registry.js";
|
import { lsType } from "./list_common.js";
|
||||||
|
import { fnType } from "../metacircular.js";
|
||||||
import {Type, Function} from "../metacircular.js";
|
import {Type, Function} from "../metacircular.js";
|
||||||
import { makeListModule } from "./list_common.js";
|
import { makeListModule } from "./list_common.js";
|
||||||
import { Module } from "./list_types/module.js";
|
import { Module } from "./list_types/module.js";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
import { fnType, lsType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import {Type, Function} from "../metacircular.js";
|
import {Type, Function} from "../metacircular.js";
|
||||||
import {Int, Byte} from "../primitives/symbols.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
|
// 'normal' implementation
|
||||||
const emptyList = {l:[]};
|
const emptyList = {l:[]};
|
||||||
|
|
@ -66,4 +72,4 @@ export const makeListModule = elementType => {
|
||||||
// {i: push , t: pushFnType},
|
// {i: push , t: pushFnType},
|
||||||
]};
|
]};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { makeListModule } from "../list_common.js";
|
import { makeListModule } from "../list_common.js";
|
||||||
import { Typed } from "../../typed.js";
|
import { Typed } from "../../typed.js";
|
||||||
import { lsType } from "../../type_registry.js";
|
import { lsType } from "../list_common.js";
|
||||||
|
|
||||||
export const Module = lsType(Typed); // a Module is a list of Typeds
|
export const Module = lsType(Typed); // a Module is a list of Typeds
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Char } from "../../primitives/symbols.js";
|
import { Char } from "../../primitives/symbols.js";
|
||||||
import { lsType } from "../../type_registry.js";
|
import { lsType } from "../list_common.js";
|
||||||
import { makeListModule } from "../list_common.js";
|
import { makeListModule } from "../list_common.js";
|
||||||
|
|
||||||
export const String = lsType(Char);
|
export const String = lsType(Char);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Type } from "../metacircular.js";
|
import { Type } from "../metacircular.js";
|
||||||
import { String } from "../structures/list_types/string.js";
|
import { String } from "../structures/list_types/string.js";
|
||||||
import { prodType } from "../type_registry.js";
|
import { prodType } from "./product.js";
|
||||||
import { makeProductType } from "./product.js";
|
import { makeProductType } from "./product.js";
|
||||||
|
|
||||||
export const NominalType = prodType(String, Type);
|
export const NominalType = prodType(String, Type);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
import { fnType, prodType } from "../type_registry.js";
|
import { fnType } from "../metacircular.js";
|
||||||
import { Function, Type } from "../metacircular.js";
|
import { Function, Type } from "../metacircular.js";
|
||||||
|
import { DefaultMap } from "../util.js";
|
||||||
|
|
||||||
|
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ operator: "product", leftType, rightType })));
|
||||||
|
|
||||||
|
// type constructor
|
||||||
|
export const prodType = (leftType, rightType) => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||||
|
|
||||||
// In JS, all products are encoded in the same way:
|
// In JS, all products are encoded in the same way:
|
||||||
const constructor = left => right => ({left, right});
|
const constructor = left => right => ({left, right});
|
||||||
|
|
@ -28,4 +34,4 @@ export const makeProductType = (leftType, rightType) => {
|
||||||
{i: constructorType , t: Function},
|
{i: constructorType , t: Function},
|
||||||
{i: constructorBoundType, t: Function},
|
{i: constructorBoundType, t: Function},
|
||||||
]};
|
]};
|
||||||
};
|
};
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
import { fnType, prodType, sumType } from "../type_registry.js";
|
import { sumType } from "../type_registry.js";
|
||||||
|
import { prodType } from "./product.js";
|
||||||
|
import { fnType } from "../metacircular.js";
|
||||||
import { Function, Type } from "../metacircular.js";
|
import { Function, Type } from "../metacircular.js";
|
||||||
import { Module } from "./list_types/module.js";
|
import { Module } from "./list_types/module.js";
|
||||||
|
|
||||||
|
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ operator: "sum", leftType, rightType })));
|
||||||
|
|
||||||
|
// type constructor
|
||||||
|
export const sumType = (leftType, rightType) => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||||
|
|
||||||
const constructorLeft = left => ({variant: "L", value: left });
|
const constructorLeft = left => ({variant: "L", value: left });
|
||||||
const constructorRight = right => ({variant: "R", value: right});
|
const constructorRight = right => ({variant: "R", value: right});
|
||||||
|
|
||||||
|
|
@ -43,4 +50,4 @@ export const makeSumType = (leftType, rightType) => {
|
||||||
|
|
||||||
{i: makeMatchFn, t: fnType({in: Type, out: Module})},
|
{i: makeMatchFn, t: fnType({in: Type, out: Module})},
|
||||||
]};
|
]};
|
||||||
};
|
};
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
// This module ensures that we never accidentally create more than one JS object for the same type twice.
|
|
||||||
// We do so by creating (nested) DefaultMap(s) for all non-nullary type constructors
|
|
||||||
// It is a cheap workaround for JS lacking customizable hash-functions and equality-testing-functions.
|
|
||||||
|
|
||||||
import { Function } from "./metacircular.js";
|
|
||||||
import { DefaultMap } from "./util.js";
|
|
||||||
|
|
||||||
|
|
||||||
const listTypeRegistry = new DefaultMap(elementType => ({listOf: elementType}));
|
|
||||||
const genericTypeRegistry = new DefaultMap(underlyingType => ({generic: underlyingType}));
|
|
||||||
const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({in: inType, out: outType})));
|
|
||||||
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({operator: "product", leftType, rightType})));
|
|
||||||
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({operator: "sum", leftType, rightType})));
|
|
||||||
|
|
||||||
|
|
||||||
export const lsType = listTypeRegistry.getdefault.bind(listTypeRegistry);
|
|
||||||
export const genericType = genericTypeRegistry.getdefault.bind(genericTypeRegistry);
|
|
||||||
export const fnType = ({in: inType, out: outType}) => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
|
||||||
export const sumType = (leftType, rightType) => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
|
||||||
export const prodType = (leftType, rightType) => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, 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}) => {
|
|
||||||
console.log('wrappedFnType called')
|
|
||||||
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})),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
// import {Type, Function, makeTypedFnInOut, fnOut} from "../metacircular.js";
|
|
||||||
// import {Bool} from "../primitives/symbols.js";
|
|
||||||
|
|
||||||
// export const Conformable = Symbol('Conformable');
|
|
||||||
// export const conformanceCheck = Symbol('conformanceCheck');
|
|
||||||
|
|
||||||
// export const ModuleConformable = [
|
|
||||||
// {i: Conformable , t: Type},
|
|
||||||
// {i: conformanceCheck, t: Function},
|
|
||||||
|
|
||||||
// // Note: outType is just 'Type', we cannot use Bool because a function that has type 'conformanceCheck' will have outType Bool, therefore conformanceCheck must return the type of Bool, which is Type.
|
|
||||||
// ...makeTypedFnInOut({f: conformanceCheck, inType: Conformable, outType: Type}),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ////////////////////////////////////////////////////////
|
|
||||||
// // Conformance check functions are themselves conformance checkable
|
|
||||||
// // This is because we want to restrict their return type to Bool
|
|
||||||
|
|
||||||
// const conformanceCheckIsConform = fn => {
|
|
||||||
// return fnOut(fn) === Bool;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const conformanceCheckIsConformFn = {name: "isConform", inType: conformanceCheck, outType: Bool, fn: conformanceCheckIsConform};
|
|
||||||
|
|
||||||
|
|
||||||
// export const ModuleConformanceCheckConforms = [
|
|
||||||
// // instances of conformanceCheck (= 'isConform'-functions) are themselves conformance checkable
|
|
||||||
// {i: conformanceCheck, t: Conformable},
|
|
||||||
// {i: conformanceCheckIsConformFn, t: conformanceCheck},
|
|
||||||
// {i: conformanceCheckIsConformFn, t: Function},
|
|
||||||
// ];
|
|
||||||
|
|
@ -1,52 +1,54 @@
|
||||||
// import {Type, Function, makeTypedFnInOut, fnIn, fnOut} from "../metacircular.js";
|
import { makeGeneric } from "../generics/generics";
|
||||||
// import {Conformable, conformanceCheck} from "./conformable.js";
|
import { addDouble, mulDouble } from "../primitives/double";
|
||||||
// import {Bool} from "../primitives/symbols.js";
|
import { addInt, mulInt } from "../primitives/int";
|
||||||
// import {deepEqual} from "../util.js";
|
import { typedFnType, typedFnType2 } from "../metacircular";
|
||||||
|
|
||||||
// export const Num = Symbol('Num');
|
const numDictTypeRegistry = new DefaultMap(a => ({numDict: a}));
|
||||||
// export const NumDict = Symbol('NumDict');
|
export const numDictType = a => numDictTypeRegistry.getdefault(a, true);
|
||||||
// // export const addType = Symbol('addType');
|
|
||||||
// // export const addBoundType = Symbol('addBoundType');
|
|
||||||
// // export const mulType = Symbol('mulType');
|
|
||||||
// // export const mulBoundType = Symbol('mulBoundType');
|
|
||||||
|
|
||||||
// // export const getType = numDict => numDict.type;
|
export const getAdd = numDict => numDict.add;
|
||||||
|
export const getMul = numDict => numDict.mul;
|
||||||
|
|
||||||
// export const getAdd = numDict => numDict.add;
|
// getAdd and getMul have same (generic) type:
|
||||||
// export const getMul = numDict => numDict.mul;
|
const [getAddMulFnType, typesOfFns] = typedFnType2(fnType =>
|
||||||
|
makeGeneric(a => fnType({
|
||||||
|
in: numDictType(a),
|
||||||
|
out: fnType({
|
||||||
|
in: a,
|
||||||
|
out: fnType({in: a, out: a}),
|
||||||
|
}),
|
||||||
|
})));
|
||||||
|
|
||||||
// // const addOrMulIsConform = fn => {
|
export const ModuleNum = {l:[
|
||||||
// // // function signature must be: a -> a -> a
|
...typedFnType(numDictType, fnType => fnType({in: Type, out: Type})),
|
||||||
// // const i0 = fnIn(fn);
|
|
||||||
// // const o0 = fnOut(fn);
|
{i: getAdd, t: getAddMulFnType},
|
||||||
// // const i1 = fnIn(o0);
|
{i: getMul, t: getAddMulFnType},
|
||||||
// // const o1 = fnOut(o0);
|
|
||||||
// // return deepEqual(i0, i1) && deepEqual(i1, o1);
|
|
||||||
// // };
|
|
||||||
|
|
||||||
// // const addIsConform = {name: "isConform", inType: addType, outType: Bool, fn: addOrMulIsConform};
|
...typesOfFns,
|
||||||
// // const mulIsConform = {name: "isConform", inType: mulType, outType: Bool, fn: addOrMulIsConform};
|
]};
|
||||||
|
|
||||||
// export const ModuleNum = [
|
|
||||||
// {i: Num, t: Type},
|
|
||||||
// {i: NumDict, t: Type},
|
|
||||||
// {i: addType, t: Type},
|
|
||||||
// {i: addBoundType, t: Type},
|
|
||||||
// {i: mulType, t: Type},
|
|
||||||
// {i: mulBoundType, t: Type},
|
|
||||||
// {i: {name: "getType", inType: NumDict, outType: Num, fn: getType}, t: Function},
|
|
||||||
// {i: {name: "getAdd", inType: NumDict, outType: addType, fn: getAdd }, t: Function},
|
|
||||||
// {i: {name: "getMul", inType: NumDict, outType: mulType, fn: getMul }, t: Function},
|
|
||||||
// ...makeTypedFnInOut({f: addType , inType: Num, outType: addBoundType}),
|
|
||||||
// ...makeTypedFnInOut({f: addBoundType, inType: Num, outType: Num }),
|
|
||||||
// ...makeTypedFnInOut({f: mulType , inType: Num, outType: mulBoundType}),
|
|
||||||
// ...makeTypedFnInOut({f: mulBoundType, inType: Num, outType: Num }),
|
|
||||||
|
|
||||||
// // conformance checking type class
|
const IntNumDict = {
|
||||||
// {i: addType, t: Conformable},
|
add: addInt,
|
||||||
// {i: mulType, t: Conformable},
|
mul: mulInt,
|
||||||
// {i: addIsConform, t: Function},
|
};
|
||||||
// {i: addIsConform, t: conformanceCheck},
|
|
||||||
// {i: mulIsConform, t: Function},
|
const DoubleNumDict = {
|
||||||
// {i: mulIsConform, t: conformanceCheck},
|
add: addDouble,
|
||||||
// ];
|
mul: mulDouble,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModuleNumInstances = {l:[
|
||||||
|
{i: IntNumDict , t: NumDict},
|
||||||
|
{i: DoubleNumDict, t: NumDict},
|
||||||
|
]};
|
||||||
|
|
||||||
|
// mapping from type to type class implementation
|
||||||
|
// in Haskell, such a mapping is global (for the entire application being compiled), and every type can implement every type class at most once.
|
||||||
|
// in Lean, such mappings can be local, and there can be multiple implementations per (type, type class).
|
||||||
|
// We have to follow Lean's approach, because in DOPE, there is no such thing as a "global scope". Every dependency is explicit, and type class resolution is just a function that always depends on a specific mapping:
|
||||||
|
export const NumInstances = new Map([
|
||||||
|
[Int , IntNumDict ],
|
||||||
|
[Double, DoubleNumDict],
|
||||||
|
]);
|
||||||
2
typed.js
2
typed.js
|
|
@ -1,4 +1,4 @@
|
||||||
import { fnType } from "./type_registry.js";
|
import { fnType } from "./metacircular.js";
|
||||||
import {Type, Function} from "./metacircular.js";
|
import {Type, Function} from "./metacircular.js";
|
||||||
|
|
||||||
export const Typed = Symbol('Typed');
|
export const Typed = Symbol('Typed');
|
||||||
|
|
|
||||||
1
util.js
1
util.js
|
|
@ -22,7 +22,6 @@ export function deepEqual(a, b) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class DefaultMap {
|
export class DefaultMap {
|
||||||
constructor(defaultValue, ...rest) {
|
constructor(defaultValue, ...rest) {
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue