add nominal types for 2D points
This commit is contained in:
parent
94efde3e65
commit
18b5e56ff0
6 changed files with 110 additions and 21 deletions
|
|
@ -15,6 +15,7 @@ export const makeGeneric = callback => {
|
|||
};
|
||||
};
|
||||
|
||||
// From the given set of type variables, return only those that occur in the given type.
|
||||
const occurring = (type, typeVars) => {
|
||||
if (typeVars.has(type)) {
|
||||
return new Set([type]);
|
||||
|
|
@ -36,7 +37,8 @@ const occurring = (type, typeVars) => {
|
|||
|
||||
// merge {i: [1], t: List_of_Int} ->
|
||||
|
||||
|
||||
// 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
|
||||
export const matchGeneric = (
|
||||
{typeVars: formalTypeVars, type: formalType},
|
||||
{typeVars: actualTypeVars, type: actualType},
|
||||
|
|
|
|||
57
lib/point.js
Normal file
57
lib/point.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { Function, Type } from "../metacircular.js";
|
||||
import { Double } from "../primitives/symbols.js";
|
||||
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
||||
import { fnType, prodType, typedFnType } from "../type_registry.js";
|
||||
|
||||
const PointCartesian2D = nominalType(
|
||||
// just a unique number, to make sure that our type is only equal to itself
|
||||
BigInt("0xBBAAD62B10EE21993BA690A732DA2A6875CE4B6F5E7139D5AEC9FD887F9D24A8"))
|
||||
(prodType(Double, Double));
|
||||
|
||||
const PointPolar2D = nominalType(
|
||||
// just a unique number, to make sure that our type is only equal to itself
|
||||
BigInt("0x31CDAB4B3D84C4EB27D3C111FD7580E533268B72E05BD694F8B262913E018B72"))
|
||||
(prodType(Double, Double));
|
||||
|
||||
export const cart2polar = ({left: x, right: y}) => {
|
||||
const r = Math.sqrt(x*x + y*y);
|
||||
const θ = Math.atan(y/x);
|
||||
return {left: r, right: θ};
|
||||
};
|
||||
|
||||
export const polar2cart = ({left: r, right: θ}) => {
|
||||
const x = r * Math.cos(θ);
|
||||
const y = r * Math.sin(θ);
|
||||
return {left: x, right: y};
|
||||
}
|
||||
|
||||
export const translate = dx => dy => ({left: x, right: y}) => {
|
||||
return {left: x+dx, right: y+dy};
|
||||
}
|
||||
|
||||
export const rotate = dθ => ({left: r, right: θ}) => {
|
||||
return {left: r, right: θ+dθ};
|
||||
}
|
||||
|
||||
export const scale = dr => ({left: r, right: θ}) => {
|
||||
return {left: r+dr, right: θ};
|
||||
}
|
||||
|
||||
export const ModulePoint = {l:[
|
||||
{i: -1 , t: Double},
|
||||
{i: 2 , t: Double},
|
||||
{i: {left: 1, right: 2}, t: PointCartesian2D},
|
||||
|
||||
{i: PointCartesian2D , t: NominalType},
|
||||
{i: PointPolar2D , t: NominalType},
|
||||
|
||||
...typedFnType(cart2polar, fnType => fnType({in: PointCartesian2D, out: PointPolar2D})),
|
||||
|
||||
...typedFnType(polar2cart, fnType => fnType({in: PointPolar2D, out: PointCartesian2D})),
|
||||
|
||||
...typedFnType(translate , fnType => fnType({in: Double, out: fnType({in: Double, out: fnType({in: PointCartesian2D, out: PointCartesian2D})})})),
|
||||
|
||||
...typedFnType(rotate, fnType => fnType({in: Double, out: fnType({in: PointPolar2D, out: PointPolar2D})})),
|
||||
|
||||
...typedFnType(scale, fnType => fnType({in: Double, out: fnType({in: PointPolar2D, out: PointPolar2D})})),
|
||||
]};
|
||||
40
main.js
40
main.js
|
|
@ -100,29 +100,31 @@ const ModuleValues = {l:[
|
|||
{i: {variant: "L", value: 100n}, t: sumType(Int, Bool)},
|
||||
]};
|
||||
|
||||
import { select } from '@inquirer/prompts';
|
||||
import { ModulePoint } from "./lib/point.js";
|
||||
|
||||
|
||||
const ctx = new Context({l:[
|
||||
...ModuleMetaCircular.l,
|
||||
...ModuleTyped.l,
|
||||
// ...ModuleConformable,
|
||||
// ...ModuleConformanceCheckConforms,
|
||||
// ...ModuleNum,
|
||||
// ...ModuleEq,
|
||||
...ModuleBool.l,
|
||||
...ModuleInt.l,
|
||||
...ModuleDouble.l,
|
||||
// ...ModuleSquare,
|
||||
// ...ModuleList,
|
||||
...makeIdFn(Int).l,
|
||||
...makeSquare({i: mulInt, t: Int_to_Int_to_Int}).l,
|
||||
...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}).l,
|
||||
...ModuleList.l,
|
||||
...ModuleValues.l,
|
||||
...ModuleModule.l,
|
||||
// ...ModuleMetaCircular.l,
|
||||
// ...ModuleTyped.l,
|
||||
// // ...ModuleConformable,
|
||||
// // ...ModuleConformanceCheckConforms,
|
||||
// // ...ModuleNum,
|
||||
// // ...ModuleEq,
|
||||
// ...ModuleBool.l,
|
||||
// ...ModuleInt.l,
|
||||
// ...ModuleDouble.l,
|
||||
// // ...ModuleSquare,
|
||||
// // ...ModuleList,
|
||||
// ...makeIdFn(Int).l,
|
||||
// ...makeSquare({i: mulInt, t: Int_to_Int_to_Int}).l,
|
||||
// ...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}).l,
|
||||
// ...ModuleList.l,
|
||||
// ...ModuleValues.l,
|
||||
// ...ModuleModule.l,
|
||||
...ModulePoint.l,
|
||||
]});
|
||||
|
||||
import { input, select } from '@inquirer/prompts';
|
||||
|
||||
const makeChoice = ([i, t]) => {
|
||||
return {
|
||||
value: {i, t: t[0]},
|
||||
|
|
|
|||
14
structures/nominal_type.js
Normal file
14
structures/nominal_type.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Type } from "../metacircular.js";
|
||||
import { Int } from "../primitives/symbols.js";
|
||||
import { prodType } from "../type_registry.js";
|
||||
import { makeProductType } from "./product.js";
|
||||
|
||||
export const NominalType = prodType(Int, Type);
|
||||
|
||||
export const ModuleNominalType = makeProductType(Int, Type);
|
||||
|
||||
export const nominalType = x => {
|
||||
const result = ModuleNominalType.l[5].i(x); // dirty!!
|
||||
result.__proto__.toString = () => "HEY";
|
||||
return result;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Maybe we shouldn't use Symbols for types, but we also cannot use primitive values for types because they may accidentally overlap with 'real' values (that are not types)
|
||||
// We also cannot use objects for types because similar to Symbols, objects are only equal to themselves if we use them as Map keys.
|
||||
|
||||
import { Function } from "./metacircular.js";
|
||||
import { DefaultMap } from "./util.js";
|
||||
|
||||
// Global store of function types:
|
||||
|
|
@ -18,6 +19,19 @@ export const fnType = ({in: inType, out: outType}) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const typedFnType = (instance, callback) => {
|
||||
const fnTs = [];
|
||||
const wrappedFnType = ({in: inType, out: outType}) => {
|
||||
const fnT = fnType({in: inType, out: outType});
|
||||
fnTs.push(fnT);
|
||||
return fnT;
|
||||
}
|
||||
return [
|
||||
{i: instance, t: callback(wrappedFnType)},
|
||||
...fnTs.map(fnT => ({i: fnT, t: Function})),
|
||||
];
|
||||
}
|
||||
|
||||
// Global store of list types:
|
||||
const listTypes = new Map();
|
||||
export const lsType = (elementType) => {
|
||||
|
|
|
|||
2
util.js
2
util.js
|
|
@ -45,5 +45,5 @@ export class DefaultMap {
|
|||
import { inspect } from 'node:util';
|
||||
|
||||
export function pretty(obj) {
|
||||
return inspect(obj, {colors: true});
|
||||
return inspect(obj, {colors: true, depth: null});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue