Skip to content

Instantly share code, notes, and snippets.

@danielbodart
Last active November 18, 2023 15:56
Show Gist options
  • Select an option

  • Save danielbodart/bd31a4b8fb8279ae35a42768d28b8e87 to your computer and use it in GitHub Desktop.

Select an option

Save danielbodart/bd31a4b8fb8279ae35a42768d28b8e87 to your computer and use it in GitHub Desktop.
Experiment with TransducerChains
/**
* 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