This commit is contained in:
Joeri Exelmans 2025-03-22 10:33:35 +01:00
parent 33c156fc5c
commit afd78c3b3e
5 changed files with 54 additions and 8 deletions

View file

@ -110,9 +110,7 @@ export const mergeSubstitutions = (m1, m2) => {
let d;
// notice we swap m2 and m1, so the rewriting can happen both ways:
[stable, m2, m1, d] = mergeOneWay(m1, m2);
if (!stable) {
deletedTypeVars = deletedTypeVars.union(d);
}
deletedTypeVars = deletedTypeVars.union(d);
}
return [new Map([...m1, ...m2]), deletedTypeVars];
}

View file

@ -2,7 +2,6 @@ import { Bool, Int } from "../primitives/symbols.js";
import { lsType } from "../structures/list_common.js";
import { fnType } from "../metacircular.js";
import { assign, makeGeneric, mergeSubstitutions, unify } from "./generics.js";
import { select } from "@inquirer/prompts";
// a -> Int
const a_to_Int = makeGeneric(a => fnType({in: a, out: Int}));

View file

@ -131,7 +131,7 @@ const makeChoice = ([i, t]) => {
return {
value: {i, t: t[0]},
name: pretty(i),
description: `${pretty(i)} :: ${pretty(t[0])}`,
description: ` :: ${pretty(t[0])}`,
short: `${pretty(i)} :: ${pretty(t[0])}`,
};
}

View file

@ -10,8 +10,56 @@ status:
2) experimental implementation of polymorphic types and type inferencing
values currently treated as white-box, hardcoded generic types (e.g., list, function) in type inferencing algorithm
todo:
wip:
- interfaces via typeclasses?
- revise the way types are encoded
we need only one 'type of type' (called 'kind' in Haskell), and we can call it 'Type'.
types explicitly contain their underlying types. the type inferencing algorithm needs this information.
Int
{ symbol: Int, params: [] }
[Int]
{ symbol: List, params: [{ symbol: Int, params: [] }] }
[[Int]]
{ symbol: List,
params: [{ symbol: List, params: [{symbol: Int, params: []}]}]}
Int -> Bool
{ symbol: Function, params: [
{ symbol: Int, params: [] },
{ symbol: Bool, params: [] },
]
}
Int | Bool
{ symbol: Sum, params: [
{ symbol: Int, params: [] },
{ symbol: Bool, params: [] },
]
}
(Int, Bool)
{ symbol: Product, params: [
{ symbol: Int, params: [] },
{ symbol: Bool, params: [] },
]
}
Point2D <-- custom nominal type! maybe it contains two Doubles, but we don't expose this
{ symbol: Point2D, params: [] }
Type constructors are just functions that return a 'Type'.
For instance:
lsType :: Type -> Type
fnType :: Type -> Type -> Type
The sad(?) part about all of this, is that I'm converging with Haskell/Lean.
- treat all values as polymorphic? (non-polymorphic values simply have empty set of type variables)
todo:
- type inferencing can be reduced to finding a graph isomorphism?

View file

@ -16,13 +16,14 @@ const squareFnType = makeGeneric(a =>
}),
}));
// should be: Int -> Int
console.log("should be: Int -> Int");
console.log(assign(squareFnType, makeGeneric(() => numDictType(Int))));
// should be: Double -> Double
console.log("should be: Double -> Double");
console.log(assign(squareFnType, makeGeneric(() => numDictType(Double))));
// to call 'square' we need:
// - access to a mapping from types to their typeclass instantiation
// - to know that our argument is 'Int'
console.log("");
console.log(square(NumInstances.get(Int))(42n)); // 1764n