import { makeGeneric } from "../../generics/generics.js"; import { makeTypeConstructor } from "../../meta/type_constructor.js"; import { makeTypeParser } from "../../parser/type_parser.js"; import { apply, newDynamic } from "../../primitives/dynamic.js"; import { Int, UUID } from "../../primitives/primitive_types.js"; import { makeModuleEnum } from "../../structures/enum.types.js"; import { makeModuleStruct } from "../../structures/struct.types.js"; import { fnType } from "../../structures/type_constructors.types.js"; export const symbolSlot = "Slot__318d1c1a9336c141336c461c6a3207b0"; export const symbolValue = "Value__23fc00a2db1374bd3dc1a0ad2d8517ab"; export const symbolTransformation = "Transformation__9eac70d7020c7c45d5a16f3f14b13083"; export const symbolWrite = "Write__abaef8ddb5c167b5d2cedac111fcefd3"; // Value and Slot each take 1 type parameter export const Slot = makeTypeConstructor(symbolSlot)(1); export const Value = makeTypeConstructor(symbolValue)(1); // Transformation takes 2 type parameters export const Transformation = makeTypeConstructor(symbolTransformation)(2); // A Write-operation writes a value to a slot. The inner type of the Value and Slot must match. export const Write = makeTypeConstructor(symbolWrite)(1); // Enum: Value const [ // constructors [, {i: newValueLiteral}], [, {i: newValueRead}], [, {i: newValueTransform}], // match function [, {i: matchValue}], ] = makeGeneric((innerType, a) => makeModuleEnum(Value(_=>innerType))([ {l: "literal" , r: innerType}, {l: "read" , r: Write(_=>innerType)}, // <- a 'read' reads the result of a Write (to a Slot) {l: "transform", r: Transformation(_=>a)(_=>innerType)}, // <- result of a function call ])); // Enum: Slot const [ // constructors [, {i: newSlotNew}], [, {i: newSlotWrite}], // match function [, {i: matchSlot}], ] = makeGeneric(innerType => makeModuleEnum(Slot(_=>innerType))([ {l: "new" , r: UUID }, {l: "write", r: Write}, ])); // Struct: Transformation (i.e., a function call) const [ // constructor [, {i: newTransformation}], // getters // [, {i: getInput}], // [, {i: getFn}], // [, {i: getOutput}], ] = makeGeneric((inType, outType) => makeModuleStruct(Transformation)([ {l: "input" , r: Value(_=>inType) }, // <- the input is a value (e.g., could be the result of a Transformation itself) {l: "fn" , r: Value(_=>fnType(_=>inType)(_=>outType)) }, // <- the function is also a value (e.g., could also be result of a transformation, e.g., when currying) {l: "output", r: outType}, // <- the result ])); // Struct: Write const [ // constructor [, {i: newWrite}], // getters // [, {i: getDepth}], // [, {i: getSlot}], // [, {i: getValue}], ] = makeGeneric(innerType => makeModuleStruct(Write(_=>innerType))([ {l: "depth", r: Int }, // <- depth increases merge performance, and also comes first in the struct (this way, it is the first value compared upon comparison) {l: "slot" , r: Slot(_=>innerType) }, {l: "value", r: Value(_=>innerType) }, ])); // shorthands export const getDepth = slot => matchSlot(slot) (_slotNew => 0n) (slotWrite => slotWrite.depth); // get the value from a Value export const getVal = value => matchValue(value) (literal => literal) (read => read.value.value) (transform => transform.output) export const write = slot => value => newSlotWrite( newWrite (getDepth(slot)+1n) (slot) (value) ); export const transform = inValue => fnValue => newValueTransform (newTransformation (inValue) (fnValue) (getVal(fnValue)(getVal(inValue))) // <- call function ); export const read = slot => matchSlot(slot) (_slotNew => { throw new Error("cannot read empty slot"); }) (write => write.value); export const newSlot = newSlotNew; export const toSlot = newSlotWrite; export const newLiteral = newValueLiteral; const mkType = makeTypeParser({ extraBracketOperators: [ [':=', ['=:', Slot]], ['*=', ['=*', Value]], ], extraInfixOperators: [ ['===>', Transformation], ], }); export const ModuleStaticVersioning = [ // slots ["newSlot" , newDynamic(newSlot )(mkType("UUID -> :=a=:" ))], ["write" , newDynamic(write )(mkType(":=a=: -> *=a=* -> :=a=:"))], ["getDepth" , newDynamic(getDepth )(mkType(":=a=: -> Int" ))], // values ["newLiteral", newDynamic(newLiteral)(mkType("a -> *=a=*" ))], ["read" , newDynamic(read )(mkType(":=a=: -> *=a=*" ))], ["transform" , newDynamic(transform )(mkType("*=a=* -> *=(a->b)=* -> *=b=*"))], ];