typescript(monadic): feat: basic stuff
Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
parent
7bdf572b2d
commit
fd81cf068e
29 changed files with 2553 additions and 299 deletions
typescript/monadic/src
42
typescript/monadic/src/environment.ts
Normal file
42
typescript/monadic/src/environment.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { IterableEmitter } from './iterableEmitter';
|
||||
|
||||
export type EnvConfig<T, S, A> = {
|
||||
render: (template: T, parent: HTMLElement) => void;
|
||||
parent: HTMLElement;
|
||||
component: Component<T, S, A>;
|
||||
initialState: S;
|
||||
};
|
||||
|
||||
export type Component<T, S, A> = {
|
||||
render: (state: S, dispatch: (a: A) => () => void) => T;
|
||||
handleActions: (action: A, state: S) => S;
|
||||
};
|
||||
|
||||
async function* runComponent<T, S, A>(
|
||||
component: Component<T, S, A>,
|
||||
initialState: S
|
||||
): AsyncGenerator<T> {
|
||||
const emitter = new IterableEmitter(initialState);
|
||||
|
||||
const dispatch = (state: S) => (action: A) => {
|
||||
const newState = component.handleActions(action, state);
|
||||
|
||||
return () => {
|
||||
emitter.next(newState);
|
||||
};
|
||||
};
|
||||
|
||||
for await (const state of emitter) {
|
||||
yield component.render(state, dispatch(state));
|
||||
}
|
||||
}
|
||||
|
||||
export const runUi = async <T, S, A>(
|
||||
config: EnvConfig<T, S, A>
|
||||
): Promise<void> => {
|
||||
const component = runComponent(config.component, config.initialState);
|
||||
|
||||
for await (const template of component) {
|
||||
config.render(template, config.parent);
|
||||
}
|
||||
};
|
110
typescript/monadic/src/hkt.ts
Normal file
110
typescript/monadic/src/hkt.ts
Normal file
|
@ -0,0 +1,110 @@
|
|||
declare const index: unique symbol;
|
||||
|
||||
/**
|
||||
* Placeholder representing an indexed type variable.
|
||||
*/
|
||||
export interface _<N extends number = 0> {
|
||||
[index]: N;
|
||||
}
|
||||
export type _0 = _<0>;
|
||||
export type _1 = _<1>;
|
||||
export type _2 = _<2>;
|
||||
export type _3 = _<3>;
|
||||
export type _4 = _<4>;
|
||||
export type _5 = _<5>;
|
||||
export type _6 = _<6>;
|
||||
export type _7 = _<7>;
|
||||
export type _8 = _<8>;
|
||||
export type _9 = _<9>;
|
||||
|
||||
declare const fixed: unique symbol;
|
||||
|
||||
/**
|
||||
* Marks a type to be ignored by the application operator `$`. This is used to protect
|
||||
* bound type parameters.
|
||||
*/
|
||||
export interface Fixed<T> {
|
||||
[fixed]: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type application (simultaneously substitutes all placeholders within the target type)
|
||||
*/
|
||||
// prettier-ignore
|
||||
export type $<T, S extends any[]> = (
|
||||
T extends Fixed<infer U> ? { [indirect]: U } :
|
||||
T extends _<infer N> ? { [indirect]: S[N] } :
|
||||
T extends undefined | null | boolean | string | number ? { [indirect]: T } :
|
||||
T extends (infer A)[] & { length: infer L } ? {
|
||||
[indirect]: L extends keyof TupleTable
|
||||
? TupleTable<T, S>[L]
|
||||
: $<A, S>[]
|
||||
} :
|
||||
T extends (...x: infer I) => infer O ? { [indirect]: (...x: $<I, S>) => $<O, S> } :
|
||||
T extends object ? { [indirect]: { [K in keyof T]: $<T[K], S> } } :
|
||||
{ [indirect]: T }
|
||||
)[typeof indirect];
|
||||
|
||||
/**
|
||||
* Used as a level of indirection to avoid circularity errors.
|
||||
*/
|
||||
declare const indirect: unique symbol;
|
||||
|
||||
/**
|
||||
* Allows looking up the type for a tuple based on its `length`, instead of trying
|
||||
* each possibility one by one in a single long conditional.
|
||||
*/
|
||||
// prettier-ignore
|
||||
type TupleTable<T extends any[] = any, S extends any[] = any> = {
|
||||
0: [];
|
||||
1: T extends [
|
||||
infer A0
|
||||
] ? [
|
||||
$<A0, S>
|
||||
] : never
|
||||
2: T extends [
|
||||
infer A0, infer A1
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>
|
||||
] : never
|
||||
3: T extends [
|
||||
infer A0, infer A1, infer A2
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>
|
||||
] : never
|
||||
4: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>
|
||||
] : never
|
||||
5: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>
|
||||
] : never
|
||||
6: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>
|
||||
] : never
|
||||
7: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>
|
||||
] : never
|
||||
8: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>
|
||||
] : never
|
||||
9: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>, $<A8, S>
|
||||
] : never
|
||||
10: T extends [
|
||||
infer A0, infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, infer A9
|
||||
] ? [
|
||||
$<A0, S>, $<A1, S>, $<A2, S>, $<A3, S>, $<A4, S>, $<A5, S>, $<A6, S>, $<A7, S>, $<A8, S>, $<A9, S>
|
||||
] : never
|
||||
}
|
|
@ -1,6 +1 @@
|
|||
export const sum = (a: number, b: number) => {
|
||||
if ('development' === process.env.NODE_ENV) {
|
||||
console.log('boop');
|
||||
}
|
||||
return a + b;
|
||||
};
|
||||
export * from './environment';
|
||||
|
|
34
typescript/monadic/src/iterableEmitter.ts
Normal file
34
typescript/monadic/src/iterableEmitter.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
// An event emitter which can be used
|
||||
// with for of loops
|
||||
export class IterableEmitter<T> {
|
||||
// The generation of the emitter
|
||||
// Used to avoid trying to resolve a promise twice
|
||||
private generation = 0;
|
||||
|
||||
// Set the state
|
||||
public next = (_: T) => {};
|
||||
|
||||
public constructor(private state: T) {}
|
||||
|
||||
async *[Symbol.asyncIterator](): AsyncGenerator<T> {
|
||||
const createPromise = () =>
|
||||
new Promise<T>(resolve => {
|
||||
const generation = this.generation;
|
||||
|
||||
this.next = (value: T) => {
|
||||
if (generation !== this.generation) {
|
||||
throw new Error('Cannot resolve the same generation twice');
|
||||
}
|
||||
|
||||
this.generation++;
|
||||
resolve(value);
|
||||
};
|
||||
});
|
||||
|
||||
yield this.state;
|
||||
|
||||
while (true) {
|
||||
yield createPromise();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue