Last active
November 18, 2023 15:56
-
-
Save danielbodart/bd31a4b8fb8279ae35a42768d28b8e87 to your computer and use it in GitHub Desktop.
Experiment with TransducerChains
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * A transducer that can be applied synchronously | |
| */ | |
| export interface Transducer<A, B> { | |
| /** | |
| * Applies the transducer to the given iterable | |
| */ | |
| (iterable: Iterable<A>): Iterable<B>; | |
| /** | |
| * Returns a string representation of the transducer | |
| */ | |
| toString(): string; | |
| } | |
| export class Sequence<T> implements Iterable<T> { | |
| constructor(public readonly source: Iterable<any>, | |
| public readonly transducers: readonly Transducer<any, any>[]) { | |
| } | |
| [Symbol.iterator](): Iterator<T> { | |
| return this.transducers.reduce((r, v) => v(r), this.source)[Symbol.iterator](); | |
| } | |
| toString(): string { | |
| return `sequence(${this.source}, ${this.transducers})`; | |
| } | |
| } | |
| export type Head<T extends any[]> = T extends [infer HEAD, ...infer IGNORE] ? HEAD : never; | |
| export type Tail<T extends any[]> = T extends [infer IGNORE, ...infer TAIL] ? TAIL : never; | |
| export type Init<T extends any[]> = T extends [...infer INIT, any] ? INIT : never; | |
| export type Last<T extends any[]> = T extends [...infer IGNORE, infer LAST] ? LAST : never; | |
| export type Input<T> = T extends Transducer<infer INPUT, any> ? INPUT : never; | |
| export type Output<T> = T extends Transducer<any, infer OUTPUT> ? OUTPUT : never; | |
| export type AnyTransducer = Transducer<any, any>; | |
| export type AnyTransducers = [...AnyTransducer[]]; | |
| export type Outputs<T extends AnyTransducers> = | |
| Init<T> extends infer F ? [any, ...Extract<{ [K in keyof F]: Output<F[K]> }, any[]>, any] : never; | |
| export type TransducerChain<T extends AnyTransducers> = | |
| { [K in keyof T]: T[K] extends Transducer<any, infer O> ? | |
| Transducer<Outputs<T>[K], O> : Transducer<Last<Outputs<T>>, any> } | |
| function Join<T extends AnyTransducers>( | |
| ...arg: T extends TransducerChain<T> ? T : TransducerChain<T> | |
| ): Transducer<Input<Head<T>>, Output<Last<T>>>; | |
| function Join(...arg: AnyTransducers): any { | |
| return null!; // impl | |
| } | |
| declare const sequence: <A, T extends AnyTransducers>(source: Iterable<A>, ...transducers: T extends TransducerChain<T> ? T : TransducerChain<T> ) | |
| => Sequence<Output<Last<T>>> ; | |
| declare const strToNum: Transducer<string, number>; | |
| declare const numToBool: Transducer<number, boolean>; | |
| const stringSink = Join(strToNum, numToBool); | |
| for (const e of stringSink('1')) { | |
| let foo: boolean = e; | |
| } | |
| //const stringSink: Sink<string> | |
| // Join(strToNum, strToNum); // error! Type 'string' is not assignable to type 'number'. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment