60 lines
1.5 KiB
JavaScript
60 lines
1.5 KiB
JavaScript
import { prodType } from "./product.js";
|
|
import { Type } from "../metacircular.js";
|
|
import { DefaultMap } from "../util.js";
|
|
import { typedFnType } from "./function.js";
|
|
import { makeGeneric } from "../generics/generics.js";
|
|
|
|
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);
|
|
|
|
const constructorLeft = left => ({variant: "L", value: left });
|
|
const constructorRight = right => ({variant: "R", value: right});
|
|
|
|
// signature:
|
|
// sum-type -> (leftType -> resultType, rightType -> resultType) -> resultType
|
|
const match = sum => handlers => sum.variant === "L"
|
|
? handlers.left(sum.value)
|
|
: handlers.right(sum.value);
|
|
|
|
export const ModuleSum = {l:[
|
|
// binary type constructor
|
|
// Type -> Type -> Type
|
|
...typedFnType(sumType, fnType => fnType
|
|
(Type)
|
|
(fnType
|
|
(Type)
|
|
(Type)
|
|
),
|
|
),
|
|
|
|
// a -> a | b
|
|
...typedFnType(constructorLeft, fnType => makeGeneric((a, b) => fnType
|
|
(a)
|
|
(sumType(a)(b))
|
|
)),
|
|
|
|
// b -> a | b
|
|
...typedFnType(constructorRight, fnType => makeGeneric((a, b) => fnType
|
|
(b)
|
|
(sumType(a)(b))
|
|
)),
|
|
|
|
// 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)
|
|
)
|
|
)),
|
|
]};
|