reorganize directory and file structure

This commit is contained in:
Joeri Exelmans 2025-05-07 13:44:49 +02:00
parent 1d826ea8d4
commit 48390b8556
99 changed files with 1155 additions and 1629 deletions

View file

@ -1,13 +1,15 @@
import { makeCompareFn } from "../compare/registry.js";
import { Int, Unit } from "../primitives/types.js";
import { unit } from "../primitives/unit.js";
import { enumType, makeConstructors, makeMatchFn } from "../structures/enum.js";
import { newProduct } from "../structures/product.js";
import { lsType, prettyT } from "../structures/types.js";
import { makeCompareFn } from "../lib/compare/registry.js";
import { Int, Unit } from "../lib/primitives/primitive_types.js";
import { unit } from "../lib/primitives/unit.js";
import { makeConstructors, makeMatchFn } from "../lib/structures/enum.js";
import { enumType } from "../lib/structures/enum.types.js";
import { newProduct } from "../lib/structures/product.js";
import { lsType } from "../lib/structures/type_constructors.js";
import { prettyT } from "../lib/util/pretty.js";
const variants = [
newProduct("price")(Int),
newProduct("prices")(lsType(() =>Int)),
newProduct("prices")(lsType(_ => Int)),
newProduct("not_found")(Unit),
];
@ -19,7 +21,7 @@ console.log(" ", prettyT(myEnumType));
const [newPrice, newPrices, newNotFound] = makeConstructors(variants);
const price = newPrice(10);
const prices = newPrices({ l: [20, 30] });
const prices = newPrices([20, 30]);
const notFound = newNotFound(unit);
console.log("observe the encoding of different variant instances:");
@ -29,7 +31,7 @@ console.log(" ", notFound);
const myEnumToString = x => makeMatchFn(variants)(x)
(price => `Price: ${price}`)
(prices => `Prices: ${prices.l}`)
(prices => `Prices: ${prices}`)
(() => "Not found!");
console.log("observe the generated match function in action:");
@ -40,9 +42,9 @@ console.log(" ", myEnumToString(notFound));
const compareMyEnum = makeCompareFn(myEnumType);
console.log("observe the generated compare function in action:");
console.log(" smaller ->", compareMyEnum(price)(prices));
console.log(" bigger ->", compareMyEnum(prices)(price));
console.log(" bigger ->", compareMyEnum(notFound)(price));
console.log(" equal ->", compareMyEnum(prices)(prices));
console.log(" smaller ->", compareMyEnum(newPrice(5))(newPrice(6)));
console.log(" bigger ->", compareMyEnum(newPrices({ l: [5, 6] }))(newPrices({ l: [5, 5] })));
console.log(" should be smaller ->", compareMyEnum(price)(prices));
console.log(" should be bigger ->", compareMyEnum(prices)(price));
console.log(" should be bigger ->", compareMyEnum(notFound)(price));
console.log(" should be equal ->", compareMyEnum(prices)(prices));
console.log(" should be smaller ->", compareMyEnum(newPrice(5))(newPrice(6)));
console.log(" should be bigger ->", compareMyEnum(newPrices([5, 6]))(newPrices([5, 5])));

View file

@ -1,45 +1,37 @@
import { Bool, Int } from "../primitives/types.js";
import { fnType, lsType } from "../structures/types.js";
import { assign, makeGeneric, unify } from "../generics/generics.js";
import { prettyGenT, prettyT } from "../util/pretty.js";
import { assign, makeGeneric, unify } from "../lib/generics/generics.js";
import { prettyGenT } from "../lib/util/pretty.js";
import { getDefaultTypeParser } from "../lib/parser/type_parser.js";
const mkType = getDefaultTypeParser();
// a -> Int
const a_to_Int = makeGeneric(a => fnType(() => a)(() => Int));
console.log((prettyGenT(a_to_Int))); // ∀a: (a -> Int)
// Bool -> Int
const Bool_to_Int = makeGeneric(() => fnType(() => lsType(() =>Bool))(() => Int));
console.log((prettyGenT(Bool_to_Int))); // ∀: ([Bool] -> Int)
console.log("should be: [Bool] -> Int")
console.log(prettyGenT(unify(a_to_Int, Bool_to_Int)));
console.log(prettyGenT(
unify(
mkType("∀a: (a -> Int)"),
makeGeneric(() => mkType("[Bool] -> Int")),
)
));
// (a -> a) -> b
const fnType2 = makeGeneric((a,b) => fnType(() => fnType(a)(a))(() => b));
// (Bool -> Bool) -> a
const fnType3 = makeGeneric(a => fnType(() => fnType(Bool)(Bool))(() => a));
console.log("should be: (Bool -> Bool) -> a");
console.log(prettyT(unify(fnType2, fnType3)));
console.log(prettyGenT(
unify(
mkType("∀a,b: (a -> a) -> b"),
mkType("∀a: (Bool -> Bool) -> a"),
)
));
// (a -> b) -> [a] -> [b]
const mapFnType = makeGeneric((a,b) =>
fnType
(fnType(() => a)(() => b))
(fnType(() => lsType(() =>a))(() => lsType(() =>b))))
// a -> a
const idFnType = makeGeneric((_,__,c) =>
fnType(() => c)(() => c));
console.log("should be: [c] -> [c]");
console.log(prettyT(assign(mapFnType, idFnType)));
console.log("should be: [a] -> [a]");
console.log(prettyGenT(
assign(
mkType("∀a,b: (a -> b) -> [a] -> [b]"),
mkType("∀a: a -> a")
)
));
// (a -> Int) -> [a] -> a
const weirdFnType = makeGeneric(a =>
fnType
(fnType(() => a)(() => Int))
(fnType
(lsType(() =>a))
(a)))
// we call this function with parameter of type (b -> b) ...
// giving these substitutions:
// a := b
// b := Int
console.log("should be: [Int] -> Int");
console.log(prettyT(assign(weirdFnType, idFnType)));
console.log(prettyGenT(
assign(
mkType("∀a: (a -> Int) -> [a] -> a"),
mkType("∀a: a -> a")
)
));

View file

@ -1,60 +0,0 @@
import { assign, makeGeneric, unify } from "../generics/generics.js";
import { Bool, Int } from "../primitives/types.js";
import { newLeft, newRight, match } from "../structures/sum.js";
import { fnType, sumType } from "../structures/types.js";
import { pretty } from '../util/pretty.js';
const IntOrBool = sumType(() => Int)(() => Bool);
// console.log(int5);
console.log(pretty(unify(
makeGeneric(() => IntOrBool),
makeGeneric(a => sumType(() => Int)(() => a)),
)));
const cipFunction = (x) => {
return match(x)({
left: x_as_int => (x_as_int === 5),
right: x_as_bool => false,
});
}
const cipFunctionType = fnType
(IntOrBool) // in
(Bool);
// console.log(cipFunctionType);
// console.log(IntOrBool);
console.log(assign(
makeGeneric(() => cipFunctionType),
makeGeneric(() => IntOrBool),
));
console.log("calling newLeft with Int:");
const typeAtCallSite = assign(
makeGeneric((a, b) =>
fnType
(a)
(sumType(() => a)(() => b))
),
makeGeneric(() => Int));
console.log(pretty(typeAtCallSite));
console.log("calling cipFunction:");
console.log(pretty(assign(
makeGeneric(() => cipFunctionType),
typeAtCallSite,
)));
console.log("valid function calls:");
console.log(cipFunction(newLeft(5)));
console.log(cipFunction(newLeft(7)));
console.log(cipFunction(newRight(true)));
console.log("invalid function calls:");
console.log(cipFunction(5));
console.log(cipFunction(newLeft("abc")));

View file

@ -1,28 +0,0 @@
import { assign } from "../generics/generics.js";
import { makeGeneric } from "../generics/generics.js";
import { Double, Int } from "../primitives/types.js";
import { fnType } from "../structures/types.js";
import { pretty } from '../util/pretty.js';
import { getMul, NumInstances } from "../typeclasses/num.js";
import { numDictType } from "./num_type.js";
const square = numDict => x => getMul(numDict)(x)(x);
// NumDict a -> a -> a
const squareFnType = makeGeneric(a =>
fnType
(numDictType(a))
(fnType(() => a)(() => a))
);
console.log("should be: Int -> Int");
console.log(pretty(assign(squareFnType, makeGeneric(() => numDictType(Int)))));
console.log("should be: Double -> Double");
console.log(pretty(assign(squareFnType, makeGeneric(() => numDictType(Double)))));
// to call 'square' we need:
// - the type of our argument (=Int)
// - access to a mapping from types to their typeclass instantiation
console.log("");
console.log(square(NumInstances.get(Int))(42n)); // 1764n

View file

@ -1,5 +1,7 @@
import { parse } from "../parser/parser.js";
import { prettyGenT, prettyT } from "../util/pretty.js";
import { getDefaultTypeParser }from "../lib/parser/type_parser.js";
import { prettyGenT, prettyT } from "../lib/util/pretty.js";
const parse = getDefaultTypeParser();
console.log(prettyT(parse("Int"))); // Int
@ -12,4 +14,3 @@ console.log(prettyT(parse("#0((Int * #0) + Unit)"))) // #0((Int #0) + Unit)
console.log(prettyGenT(parse("∀a: #0((a * #0) + Unit"))); // ∀a: #0((a #0) + Unit)
console.log(prettyGenT(parse("∀a,b,c,d: (a*b) + (c*d)"))); // ∀a,b,c,d: ((a b) + (c d))

View file

@ -1,14 +1,15 @@
import { select, number, input } from '@inquirer/prompts';
import { ModulePoint } from "../lib/point.js";
import { DefaultMap } from "../util/defaultmap.js";
import { pretty } from '../util/pretty.js';
import { DefaultMap } from "../lib/util/defaultmap.js";
import { pretty } from '../lib/util/pretty.js';
import { isFunction } from '../structures/types.js';
import { ModuleStd } from '../stdlib.js';
import { ModuleStd } from '../lib/stdlib.js';
import { Double, GenericType, Int, SymbolT, Type } from "../primitives/types.js";
import { eqType } from '../primitives/type.js';
import { Top } from "../primitives/types.js";
import { assignFn, makeGeneric, onlyOccurring } from '../generics/generics.js';
import { prettyT } from '../util/pretty.js';
import { assignFn, makeGeneric, onlyOccurring } from '../lib/generics/generics.js';
import { prettyT } from '../lib/util/pretty.js';
import { genUUID } from '../lib/util/random.js';
// import {emitKeypressEvents} from 'node:readline';
@ -289,7 +290,7 @@ async function createInstance(t) {
else if (eqType(t)(SymbolT)) {
console.log("Note: you are creating a new Symbol. Even if the description matches that of another symbol (e.g., \"Int\"), a new Symbol will be created that is unique and only equal to itself.");
const symbolDescr = await input({message: "enter symbol description:"});
return Symbol(symbolDescr);
return symbolDescr + '__' + genUUID(16);
}
else {
console.log("no prompt handler for creating new", prettyT(t));

13
examples/rbtree.js Normal file
View file

@ -0,0 +1,13 @@
import createRBTree from "functional-red-black-tree";
console.log("#############");
console.log("## RB Tree ##");
console.log("#############");
// just a small experiment
console.log(
createRBTree()
.insert(1)
.insert(1)
.insert(2)
);

View file

@ -1,88 +0,0 @@
import createTree from "functional-red-black-tree";
function benchmark(N) {
// fastest
function map() {
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durInPlace = map();
console.log("in-place:", durInPlace, "ms");
// slower by constant factor
function fun() {
let t = createTree();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t = t.insert(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durFunc = fun();
console.log("functional:", durFunc, "ms");
// a bit slower still
function funNoGC() {
const old = new Array(N);
let t = createTree();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
old[i] = t; // prevent garbage collection
t = t.insert(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durFuncNoGC = (N <= 1000000) ? funNoGC() : "";
console.log("functional (no GC):", durFuncNoGC, "ms");
// slowest (won't scale)
function copying() {
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t = new Map(t);
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durCopying = (N <= 50000) ? copying() : "";
console.log("copying:", durCopying, "ms");
// slower than slowest
function copyingNoGC() {
const old = new Array(N);
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
old[i] = t; // prevent garbage collection
t = new Map(t);
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durCopyingNoGC = (N <= 10000) ? copyingNoGC() : "";
console.log("copying (no GC):", durCopyingNoGC, "ms");
return [N, durInPlace, durFunc, durFuncNoGC, durCopying, durCopyingNoGC];
}
const results = [];
for (const N of [100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000]) {
console.log("N =", N);
results.push(benchmark(N));
}
console.log("N;in-place;functional;functional-NoGC;copying;copying-NoGC");
for (const [N, durInPlace, durFunc, durFuncNoGC, durCopying, durCopyingNoGC] of results) {
console.log(`${N};${durInPlace};${durFunc};${durFuncNoGC};${durCopying};${durCopyingNoGC}`);
}

View file

@ -1,8 +1,10 @@
import { compareTypes } from "../compare/type.js";
import { makeGeneric, substitute, unify } from "../generics/generics.js";
import { Double, Int, Unit } from "../primitives/types.js";
import { fnType, lsType, prodType, setType, sumType } from "../structures/types.js";
import { prettyGenT, prettyT } from "../util/pretty.js";
import { compareTypes } from "../lib/compare/type.js";
import { makeGeneric, substitute, unify } from "../lib/generics/generics.js";
import { Double, Int, Unit } from "../lib/primitives/primitive_types.js";
import { fnType, lsType, prodType, sumType, setType } from "../lib/structures/type_constructors.js";
import { prettyGenT, prettyT } from "../lib/util/pretty.js";
Error.stackTraceLimit = Infinity;
// some recursive types:

View file

@ -1,7 +1,6 @@
import { pretty } from "../util/pretty.js";
import { newLiteral, transform, read, getReadDependencies, verifyValue } from "../versioning/value.js";
import { merge, merge2, newSlot, overwrite } from "../versioning/slot.js";
import createRBTree from "functional-red-black-tree";
import { add, emptySet, RBTreeWrapper } from "../structures/set.js";
import { compareNumbers } from "../compare/primitives.js";
@ -77,39 +76,20 @@ console.log(pretty({sixSevenEightSlot}));
// console.log("########################");
// console.log("## Heterogeneous data ##");
// console.log("########################");
// // Slot<Int>
// const numberOfSheepSlot = newSlot(Symbol('numberOfSheep'))(newLiteral(5));
// const alternativeNumberOfSheepSlot = newSlot(Symbol('alternativeNumberOfSheep'))(newLiteral(6));
// // Slot<String>
// const labelSlot = newSlot(Symbol('label'))(newLiteral("number of sheep"));
// const combineFn = newLiteral(label => numberOfSheep => `${label}: ${numberOfSheep}`)
// // Slot<String>
// const labelAndValueSlotA = overwrite(labelSlot)(
// transform(read(numberOfSheepSlot))(
// transform(read(labelSlot))(combineFn)));
// const labelAndValueSlotB = overwrite(labelSlot)(
// transform(read(alternativeNumberOfSheepSlot))(
// transform(read(labelSlot))(combineFn)));
// console.log(
// add(add(emptySet(compareSlots(compareStrings)))(labelAndValueSlotA))(labelAndValueSlotB)
// );
// merge()(labelSlot)(labelAndValueSlot)
console.log("#############")
console.log("## RB Tree ##")
console.log("#############")
// just a small experiment
console.log(
createRBTree()
.insert(1)
.insert(1)
.insert(2)
);