rename dir scripts -> examples
This commit is contained in:
parent
bc9dce4b9c
commit
28f60e77be
7 changed files with 0 additions and 0 deletions
48
examples/enum.js
Normal file
48
examples/enum.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
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 { constructorProduct } from "../structures/product.js";
|
||||
import { lsType, prettyT } from "../structures/types.js";
|
||||
|
||||
const variants = [
|
||||
constructorProduct("price")(Int),
|
||||
constructorProduct("prices")(lsType(Int)),
|
||||
constructorProduct("not_found")(Unit),
|
||||
];
|
||||
|
||||
const myEnumType = enumType(variants);
|
||||
|
||||
console.log("observe the type that was generated:");
|
||||
console.log(" ", prettyT(myEnumType));
|
||||
|
||||
const [newPrice, newPrices, newNotFound] = makeConstructors(variants);
|
||||
|
||||
const price = newPrice(10);
|
||||
const prices = newPrices({ l: [20, 30] });
|
||||
const notFound = newNotFound(unit);
|
||||
|
||||
console.log("observe the encoding of different variant instances:");
|
||||
console.log(" ", price);
|
||||
console.log(" ", prices);
|
||||
console.log(" ", notFound);
|
||||
|
||||
const myEnumToString = x => makeMatchFn(variants)(x)
|
||||
(price => `Price: ${price}`)
|
||||
(prices => `Prices: ${prices.l}`)
|
||||
(() => "Not found!");
|
||||
|
||||
console.log("observe the generated match function in action:");
|
||||
console.log(" ", myEnumToString(price));
|
||||
console.log(" ", myEnumToString(prices));
|
||||
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] })));
|
||||
42
examples/generics.js
Normal file
42
examples/generics.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { Bool, Int } from "../primitives/types.js";
|
||||
import { fnType, lsType, prettyT } from "../structures/types.js";
|
||||
import { assign, makeGeneric, unify } from "../generics/generics.js";
|
||||
|
||||
// a -> Int
|
||||
const a_to_Int = makeGeneric(a => fnType(a)(Int));
|
||||
// Bool -> Int
|
||||
const Bool_to_Int = makeGeneric(() => fnType(lsType(Bool))(Int));
|
||||
console.log("should be: [Bool] -> Int")
|
||||
console.log(prettyT(unify(a_to_Int, Bool_to_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)));
|
||||
|
||||
// (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)));
|
||||
|
||||
// (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)));
|
||||
60
examples/int_or_bool.js
Normal file
60
examples/int_or_bool.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { assign, makeGeneric, unify } from "../generics/generics.js";
|
||||
import { Bool, Int } from "../primitives/types.js";
|
||||
import { constructorLeft, constructorRight, 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 constructorLeft 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(constructorLeft(5)));
|
||||
console.log(cipFunction(constructorLeft(7)));
|
||||
console.log(cipFunction(constructorRight(true)));
|
||||
|
||||
console.log("invalid function calls:");
|
||||
console.log(cipFunction(5));
|
||||
console.log(cipFunction(constructorLeft("abc")));
|
||||
447
examples/main.js
Normal file
447
examples/main.js
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
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 { isFunction, prettyT } from '../structures/types.js';
|
||||
import { ModuleStd } from '../stdlib.js';
|
||||
import { Double, GenericType, Int, SymbolT, Type } from "../primitives/types.js";
|
||||
import { eqType } from '../primitives/type.js';
|
||||
import { Any } from "../primitives/types.js";
|
||||
import { assignFn, makeGeneric, onlyOccurring } from '../generics/generics.js';
|
||||
|
||||
|
||||
// import {emitKeypressEvents} from 'node:readline';
|
||||
|
||||
// // Configure readline to read from stdin
|
||||
// emitKeypressEvents(process.stdin);
|
||||
// process.stdin.setRawMode(true);
|
||||
|
||||
// console.log('Press any key (ESC to exit)...');
|
||||
|
||||
// process.stdin.on('keypress', (str, key) => {
|
||||
// if (key.name === 'escape') {
|
||||
// console.log('Escape key pressed!');
|
||||
// process.exit();
|
||||
// }
|
||||
// });
|
||||
|
||||
const prettyIT = ({i, t}) => ({
|
||||
strI: isType(i) ? prettyT(i) : pretty(i),
|
||||
strT: prettyT(t),
|
||||
// strI: pretty(i),
|
||||
// strT: pretty(t),
|
||||
});
|
||||
|
||||
const isType = i => i.typeVars || i.symbol;
|
||||
// ctx.types.getdefault(i).has(Type)
|
||||
// || ctx.types.getdefault(i).has(GenericType);
|
||||
|
||||
class Context {
|
||||
constructor(mod) {
|
||||
this.mod = mod;
|
||||
this.types = new DefaultMap(() => new Set()); // instance to type
|
||||
this.instances = new DefaultMap(() => new Set()); // type to instance
|
||||
|
||||
for (const {i, t} of mod.l) {
|
||||
const {strI, strT} = prettyIT({i,t})
|
||||
// console.log(strI, '::', strT);
|
||||
|
||||
this.types.getdefault(i, true).add(t);
|
||||
this.types.getdefault(i, true).add(Any);
|
||||
if (t.typeVars) {
|
||||
// console.log("generic:", prettyT(t));
|
||||
this.types.getdefault(t, true).add(GenericType);
|
||||
}
|
||||
else {
|
||||
// console.log("non-generic:", prettyT(t));
|
||||
this.types.getdefault(t, true).add(Type);
|
||||
}
|
||||
|
||||
this.instances.getdefault(t, true).add(i);
|
||||
this.instances.getdefault(Any, true).add(i);
|
||||
}
|
||||
const addIfFunctionType = (t, originalT, add) => {
|
||||
if (isFunction(t)) {
|
||||
for (const fn of this.instances.getdefault(originalT)) {
|
||||
add(fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.functions = [];
|
||||
for (const type of this.instances.getdefault(Type)) {
|
||||
addIfFunctionType(type, type, fn => this.functions.push({fn, type}));
|
||||
}
|
||||
this.genericFunctions = [];
|
||||
for (const genericType of this.instances.getdefault(GenericType)) {
|
||||
addIfFunctionType(genericType.type, genericType, fn => this.genericFunctions.push({fn, genericType}));
|
||||
}
|
||||
}
|
||||
|
||||
addToCtx({i, t}) {
|
||||
return new Context({l:[
|
||||
...this.mod.l,
|
||||
{i, t},
|
||||
]});
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = new Context({l:[
|
||||
...ModuleStd.l,
|
||||
...ModulePoint.l,
|
||||
]});
|
||||
|
||||
const toChoices = ([i, types]) => {
|
||||
return [...types].map(t => {
|
||||
const {strI, strT} = prettyIT({i, t});
|
||||
return {
|
||||
value: {i, t},
|
||||
name: strI,
|
||||
description: ` :: ${strT}`,
|
||||
short: `${strI} :: ${strT}`,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
async function topPrompt() {
|
||||
const action = await select({
|
||||
message: "What do you want to do?",
|
||||
choices: [
|
||||
"list all types",
|
||||
"list all generic types",
|
||||
"list all functions",
|
||||
"list all",
|
||||
],
|
||||
});
|
||||
if (action === "list all types") {
|
||||
await listInstances(Type);
|
||||
}
|
||||
if (action === "list all generic types") {
|
||||
await listInstances(GenericType);
|
||||
}
|
||||
if (action === "list all functions") {
|
||||
await listAllFunctions();
|
||||
}
|
||||
if (action === "list all") {
|
||||
await listAll();
|
||||
}
|
||||
return topPrompt();
|
||||
}
|
||||
|
||||
async function listAllFunctions() {
|
||||
const choice = await select({
|
||||
message: "select function:",
|
||||
choices: [
|
||||
"(go back)",
|
||||
...ctx.functions.flatMap(({fn, type}) => toChoices([fn, [type]])),
|
||||
...ctx.genericFunctions.flatMap(({fn, genericType}) => toChoices([fn, [genericType]])),
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
const {i, t} = choice;
|
||||
await functionOptions(i, t);
|
||||
return listAllFunctions();
|
||||
}
|
||||
|
||||
async function typeOptions(t, tt) {
|
||||
const choice = await select({
|
||||
message: `actions for type ${prettyT(t)} :: ${prettyT(tt)}`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
"create instance",
|
||||
"list instances",
|
||||
// "list outgoing functions",
|
||||
// "list incoming functions",
|
||||
"print raw",
|
||||
"treat as instance",
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
else if (choice === "create instance") {
|
||||
const i = await createInstance(t);
|
||||
if (i !== undefined) {
|
||||
ctx = ctx.addToCtx({i, t});
|
||||
return instanceOrTypeOrFnOptions({i, t});
|
||||
}
|
||||
}
|
||||
else if (choice === "list instances") {
|
||||
await listInstances(t);
|
||||
}
|
||||
else if (choice === "print raw") {
|
||||
console.log(pretty(t));
|
||||
}
|
||||
else if (choice === "treat as instance") {
|
||||
await instanceOptions(t, tt)
|
||||
}
|
||||
else {
|
||||
console.log("unimplemented:", choice);
|
||||
}
|
||||
return typeOptions(t, tt);
|
||||
}
|
||||
|
||||
async function listAll() {
|
||||
const choice = await select({
|
||||
message: `all instances:`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
... [...ctx.types.m.keys()].flatMap(i => toChoices([i, ctx.types.getdefault(i)])),
|
||||
],
|
||||
})
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
return instanceOrTypeOrFnOptions(choice);
|
||||
}
|
||||
|
||||
async function instanceOrTypeOrFnOptions({i, t}) {
|
||||
if (t.typeVars) {
|
||||
if (isFunction(t.type)) {
|
||||
return functionOptions(i, t);
|
||||
}
|
||||
}
|
||||
if (isFunction(t)) {
|
||||
return functionOptions(i, t);
|
||||
}
|
||||
if (t === Type || t === GenericType) {
|
||||
return typeOptions(i, t);
|
||||
}
|
||||
return instanceOptions(i,t);
|
||||
}
|
||||
|
||||
async function listInstances(t) {
|
||||
const choice = await select({
|
||||
message: `instances of ${prettyT(t)}:`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
... [...ctx.instances.getdefault(t)].flatMap(i => toChoices([i, [t]])),
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
return instanceOrTypeOrFnOptions(choice);
|
||||
}
|
||||
|
||||
async function listTypes(i) {
|
||||
const {strI} = prettyIT({i,t:Type});
|
||||
const choice = await select({
|
||||
message: `type(s) of ${strI}:`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
... [...ctx.types.getdefault(i)].flatMap(t => toChoices([t, ctx.types.getdefault(t)])),
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
const {i: chosenType, t: typeOfChosenType} = choice;
|
||||
await typeOptions(chosenType, typeOfChosenType);
|
||||
return listTypes(i);
|
||||
}
|
||||
|
||||
async function functionOptions(fn, fnT) {
|
||||
const {strI, strT} = prettyIT({i: fn, t: fnT});
|
||||
const choice = await select({
|
||||
message: `actions for function ${strI} :: ${strT}`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
"call",
|
||||
"treat as instance",
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
if (choice === "call") {
|
||||
await callFunction(fn, fnT);
|
||||
}
|
||||
if (choice === "treat as instance") {
|
||||
await instanceOptions(fn, fnT);
|
||||
}
|
||||
return functionOptions(fn, fnT);
|
||||
}
|
||||
|
||||
async function createInstance(t) {
|
||||
if (t.typeVars && t.typeVars.size === 0) {
|
||||
t = t.type; // can treat as non-generic
|
||||
}
|
||||
if (eqType(t)(Int)) {
|
||||
const n = await number({
|
||||
message: `enter an integer (leave empty to go back):`,
|
||||
step: 1, // only integers
|
||||
});
|
||||
if (n === undefined) {
|
||||
return;
|
||||
}
|
||||
return BigInt(n);
|
||||
}
|
||||
else if (eqType(t)(Double)) {
|
||||
const n = await number({
|
||||
message: `enter a number (leave empty to go back):`,
|
||||
step: 'any',
|
||||
});
|
||||
return n;
|
||||
}
|
||||
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);
|
||||
}
|
||||
else {
|
||||
console.log("no prompt handler for creating new", prettyT(t));
|
||||
}
|
||||
}
|
||||
|
||||
async function callFunction(fn, fnT) {
|
||||
const {strI, strT} = prettyIT({i: fn, t: fnT});
|
||||
let choices;
|
||||
let inType;
|
||||
if (fnT.typeVars) {
|
||||
// generic
|
||||
choices = [...ctx.types.m.entries()].flatMap(([i, types]) => {
|
||||
return [...types].flatMap(t => {
|
||||
const genT = t.typeVars ? t : makeGeneric(() => t);
|
||||
let assignedFnType;
|
||||
try {
|
||||
assignedFnType = assignFn(fnT, genT);
|
||||
} catch (e) {
|
||||
if (e.message.startsWith("cannot unify")) {
|
||||
// console.warn(e);
|
||||
return [];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
const assignedInType = onlyOccurring(assignedFnType.type.params[0], assignedFnType.typeVars);
|
||||
if (assignedInType.typeVars.size > 0) {
|
||||
return toChoices([i, [assignedInType]]);
|
||||
}
|
||||
else {
|
||||
return toChoices([i, [assignedInType.type]]);
|
||||
}
|
||||
});
|
||||
});
|
||||
inType = onlyOccurring(fnT.type.params[0], fnT.typeVars)
|
||||
}
|
||||
else {
|
||||
inType = fnT.params[0];
|
||||
choices = [...ctx.instances.getdefault(inType)].flatMap(i => toChoices([i, [inType]]));
|
||||
}
|
||||
|
||||
const choice = await select({
|
||||
message: `select parameter of type ${prettyT(inType)} for function ${strI} :: ${strT}`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
"(new)",
|
||||
...choices,
|
||||
],
|
||||
});
|
||||
let i, t;
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
else if (choice === "(new)") {
|
||||
i = await createInstance(inType);
|
||||
t = inType;
|
||||
if (i === undefined) {
|
||||
return callFunction(fn, fnT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = choice.i;
|
||||
t = choice.t;
|
||||
}
|
||||
const genT = t.typeVars ? t : makeGeneric(() => t);
|
||||
const genFnT = fnT.typeVars ? fnT : makeGeneric(() => fnT);
|
||||
const assignedFnType = assignFn(genFnT, genT);
|
||||
await apply(i, fn, assignedFnType);
|
||||
return callFunction(fn, fnT);
|
||||
}
|
||||
|
||||
async function instanceOptions(i,t) {
|
||||
const {strI, strT} = prettyIT({i,t});
|
||||
const choice = await select({
|
||||
message: `actions for instance ${strI} :: ${strT}`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
"transform",
|
||||
"list type(s)",
|
||||
]
|
||||
})
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
if (choice === "transform") {
|
||||
await transform(i, t)
|
||||
}
|
||||
if (choice === "list type(s)") {
|
||||
await listTypes(i);
|
||||
}
|
||||
return await instanceOptions(i,t);
|
||||
}
|
||||
|
||||
async function transform(i, t) {
|
||||
const {strI, strT} = prettyIT({i, t});
|
||||
// console.log(ctx.functionsFrom.getdefault(t));
|
||||
|
||||
const genT = t.typeVars ? t : makeGeneric(() => t);
|
||||
|
||||
const choice = await select({
|
||||
message: `choose transformation to perform on ${strI} :: ${strT}`,
|
||||
choices: [
|
||||
"(go back)",
|
||||
|
||||
...ctx.functions
|
||||
.filter(({type}) => {
|
||||
// console.log(type.params[0], t);
|
||||
return eqType(type.params[0])(t)
|
||||
})
|
||||
.flatMap(({fn, type}) => toChoices([fn, [type]])),
|
||||
|
||||
...ctx.genericFunctions
|
||||
.flatMap(({fn, genericType}) => {
|
||||
let fnType;
|
||||
try {
|
||||
fnType = assignFn(genericType, genT);
|
||||
} catch (e) {
|
||||
if (e.message.startsWith("cannot unify")) {
|
||||
// console.warn(e);
|
||||
return [];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return toChoices([fn, [fnType]]);
|
||||
}),
|
||||
],
|
||||
});
|
||||
if (choice === "(go back)") {
|
||||
return;
|
||||
}
|
||||
|
||||
const {i:fn,t:fnT} = choice;
|
||||
await apply(i, fn, fnT);
|
||||
return transform(i, t);
|
||||
}
|
||||
|
||||
async function apply(i, fn, fnT) {
|
||||
const result = fn(i);
|
||||
let resultType;
|
||||
if (fnT.typeVars) {
|
||||
const res = onlyOccurring(fnT.type.params[1], fnT.typeVars);
|
||||
resultType = res.typeVars.size > 0 ? res : res.type;
|
||||
}
|
||||
else {
|
||||
resultType = fnT.params[1];
|
||||
}
|
||||
// update context with newly produced value
|
||||
ctx = ctx
|
||||
.addToCtx({i: result, t: resultType})
|
||||
.addToCtx({i: resultType, t: resultType.typeVars ? GenericType : Type});
|
||||
const {strI: strResult, strT: strResultType} = prettyIT({i: result, t: resultType});
|
||||
console.log(`result = ${strResult} :: ${strResultType}`);
|
||||
return instanceOrTypeOrFnOptions({i: result, t: resultType});
|
||||
}
|
||||
|
||||
topPrompt();
|
||||
28
examples/num.js
Normal file
28
examples/num.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
88
examples/rbtree_bench.js
Normal file
88
examples/rbtree_bench.js
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
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}`);
|
||||
}
|
||||
115
examples/versioning.js
Normal file
115
examples/versioning.js
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
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";
|
||||
|
||||
const inc = x => x + 1;
|
||||
|
||||
|
||||
console.log("##############");
|
||||
console.log("## Counting ##");
|
||||
console.log("##############");
|
||||
|
||||
const counterOneSlot = newSlot(Symbol('counter'))(newLiteral(1));
|
||||
const valueOne = read(counterOneSlot);
|
||||
console.log(pretty({valueOne}));
|
||||
const onePlusOne = transform(valueOne)(newLiteral(inc));
|
||||
console.log(pretty({onePlusOne}));
|
||||
const onePlusOnePlusOne = transform(onePlusOne)(newLiteral(inc));
|
||||
console.log(pretty({onePlusOnePlusOne}));
|
||||
|
||||
verifyValue(valueOne);
|
||||
verifyValue(onePlusOne);
|
||||
verifyValue(onePlusOnePlusOne);
|
||||
|
||||
|
||||
|
||||
console.log("#############");
|
||||
console.log("## Summing ##");
|
||||
console.log("#############");
|
||||
|
||||
const priceSlot = newSlot(Symbol('price'))(newLiteral(20.66));
|
||||
const taxSlot = newSlot(Symbol('tax'))(newLiteral(4.34));
|
||||
|
||||
const total =
|
||||
transform(read(priceSlot))(
|
||||
transform(read(taxSlot))(
|
||||
newLiteral(tax => price => price + tax)));
|
||||
|
||||
console.log(pretty({total}))
|
||||
|
||||
const totalPlusOne = transform(total)(newLiteral(inc));
|
||||
|
||||
console.log(pretty({totalPlusOne}));
|
||||
|
||||
verifyValue(totalPlusOne);
|
||||
|
||||
console.log("getReadDependencies(totalPlusOne):", getReadDependencies(totalPlusOne));
|
||||
|
||||
|
||||
|
||||
console.log("###############");
|
||||
console.log("## Branching ##");
|
||||
console.log("###############");
|
||||
|
||||
const fiveSlot = newSlot(Symbol('counter'))(newLiteral(5));
|
||||
const sixSlot = overwrite(fiveSlot)(newLiteral(6));
|
||||
const sevenSlot = overwrite(fiveSlot)(newLiteral(7));
|
||||
const eightSlot = overwrite(fiveSlot)(newLiteral(8));
|
||||
|
||||
const intMerge = merge(compareNumbers);
|
||||
const intMerge2 = merge2(compareNumbers);
|
||||
|
||||
const sixSevenSlot = intMerge(sixSlot)(sevenSlot);
|
||||
const sevenEightSlot = intMerge(sevenSlot)(eightSlot);
|
||||
|
||||
// console.log(compareSlots(intCompare)(fiveSlot)(fiveSlot));
|
||||
// console.log(compareSlots(intCompare)(sixSlot)(sixSlot));
|
||||
// console.log(compareSlots(intCompare)(fiveSlot)(sixSlot));
|
||||
// console.log(compareSlots(intCompare)(sixSlot)(fiveSlot));
|
||||
|
||||
const sixSevenEightSlot = intMerge2(sixSevenSlot)(sevenEightSlot);
|
||||
|
||||
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)
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue