import { MonadPlus } from '../monadplus'; export class Sequence extends MonadPlus implements Iterable { constructor( protected readonly cons: (z: z, cons: (a?: a, z?: z) => Sequence.Data) => Sequence.Data ) { super(throwCallError); } public [Symbol.iterator](): Iterator { let iter = () => this.iterate(); return { next() { const thunk = iter(); iter = Sequence.Thunk.iterator(thunk); return { done: !Sequence.isIterable(thunk), value: Sequence.Thunk.value(thunk) } as IteratorResult; } }; } } export namespace Sequence { export declare function resume(iterator: Sequence.Iterator): Sequence>; export declare function from(as: Iterable): Sequence>]>; export declare function cycle(as: Iterable): Sequence>]>; export declare function random(): Sequence>]>; export declare function random(gen: () => a): Sequence>]>; export declare function random(as: a[]): Sequence>; export declare function concat(as: Sequence, unknown>): Sequence>, Sequence.Iterator]>; export declare function zip(a: Sequence, b: Sequence): Sequence<[a, b], [Sequence.Iterator, Sequence.Iterator]>; export declare function difference(a: Sequence, b: Sequence, cmp: (l: a, r: a) => number): Sequence, Sequence.Iterator]>; export declare function union(a: Sequence, b: Sequence, cmp: (l: a, r: a) => number): Sequence, Sequence.Iterator]>; export declare function intersect(a: Sequence, b: Sequence, cmp: (l: a, r: a) => number): Sequence, Sequence.Iterator]>; export declare function fmap(f: (a: a) => b, m: Sequence): Sequence>; export declare function pure(a: a): Sequence; export declare function ap(mf: Sequence<(a: a) => b, unknown>, ma: Sequence): Sequence>, Sequence.Iterator]>; export declare function ap(mf: Sequence<(a: a) => b, unknown>): (ma: Sequence) => Sequence>, Sequence.Iterator]>; export declare const Return: typeof pure; export declare function bind(f: (a: a) => Sequence, m: Sequence): Sequence>; export declare function sequence(ms: Sequence[]): Sequence, Sequence.Iterator]>, Sequence.Iterator, Sequence.Iterator]>>>; export declare const mempty: Sequence; export declare function mappend(l: Sequence, r: Sequence): Sequence, Sequence.Iterator]>; export declare function mconcat(as: Iterable>): Sequence, Sequence.Iterator]>; export declare const mzero: Sequence; export declare function mplus(l: Sequence, r: Sequence): Sequence, Sequence.Iterator]>; } export interface Sequence { extract(): a[]; [Symbol.iterator](): Iterator; iterate(): Sequence.Thunk; fmap(f: (a: a) => b): Sequence>; ap(this: Sequence<(a: a) => z, unknown>, a: Sequence): Sequence>, Sequence.Iterator]>; ap(this: Sequence<(a: a, b: b) => z, unknown>, a: Sequence): Sequence<(b: b) => z, [Sequence.Iterator>, Sequence.Iterator]>; ap(this: Sequence<(a: a, b: b, c: c) => z, unknown>, a: Sequence): Sequence<(b: b, c: c) => z, [Sequence.Iterator>, Sequence.Iterator]>; ap(this: Sequence<(a: a, b: b, c: c, d: d) => z, unknown>, a: Sequence): Sequence<(b: b, c: c, d: d) => z, [Sequence.Iterator>, Sequence.Iterator]>; ap(this: Sequence<(a: a, b: b, c: c, d: d, e: e) => z, unknown>, a: Sequence): Sequence<(b: b, c: c, d: d, e: e) => z, [Sequence.Iterator>, Sequence.Iterator]>; bind(f: (a: a) => Sequence): Sequence>, Sequence.Iterator]>; join(this: Sequence, unknown>): Sequence>, Sequence.Iterator]>; mapM(f: (a: a) => Sequence): Sequence>, Sequence.Iterator]>; filterM(f: (a: a) => Sequence): Sequence>, Sequence.Iterator]>; map(f: (a: a, i: number) => b): Sequence>; filter(f: (a: a, i: number) => boolean): Sequence>; scanl(f: (b: b, a: a) => b, z: b): Sequence, number]>; foldr(f: (a: a, b: Sequence) => Sequence, z: Sequence): Sequence>, Sequence.Iterator]>; group(f: (x: a, y: a) => boolean): Sequence, a[]]>; inits(): Sequence, Sequence.Iterator]> tails(): Sequence, Sequence.Iterator]> segs(): Sequence, Sequence.Iterator]>; subsequences(): Sequence, Sequence.Iterator]>; permutations(): Sequence>, Sequence.Iterator]>; take(n: number): Sequence>; drop(n: number): Sequence>; takeWhile(f: (a: a) => boolean): Sequence>; dropWhile(f: (a: a) => boolean): Sequence>; takeUntil(f: (a: a) => boolean): Sequence>; dropUntil(f: (a: a) => boolean): Sequence>; sort(cmp?: (a: a, b: a) => number): Sequence>]>; unique(): Sequence>; memoize(): Sequence>]>; reduce(): Sequence>]>; } export namespace Sequence { export type Data = [] | [a] | [a, z]; export namespace Data { export function cons(): []; export function cons(a: a): [a]; export function cons(a: a, z: z): [a, z]; export function cons(a?: a, z?: z): Data { switch (arguments.length) { case 0: return []; case 1: return [a!]; case 2: return [a!, z!]; default: throw Sequence.Exception.invalidConsError(arguments); } } } export type Thunk = [a, Iterator, number]; export namespace Thunk { export function value(thunk: Thunk): a { return thunk[0]; } export function iterator(thunk: Thunk): Iterator { return thunk[1]; } export function index(thunk: Thunk): number { return thunk[2]; } } export type Iterator = () => Thunk; export namespace Iterator { export const done: Sequence.Iterator = () => >[undefined, done, -1]; export function when( thunk: Thunk, caseDone: (thunk: Thunk) => b, caseIterable: (thunk: Thunk, recur: () => b) => b ): b { return Sequence.isIterable(thunk) ? caseIterable(thunk, () => when(Thunk.iterator(thunk)(), caseDone, caseIterable)) : caseDone(thunk); } } export function isIterable(thunk: Thunk): boolean { return Thunk.iterator(thunk) !== Iterator.done; } export namespace Exception { export function invalidConsError(args: IArguments): TypeError { console.error(args, args.length, args[0], args[1]); return new TypeError(`Spica: Sequence: Invalid parameters of cons`); } export function invalidDataError(data: unknown[]): TypeError { console.error(data); return new TypeError(`Spica: Sequence: Invalid data`); } export function invalidThunkError(thunk: Sequence.Thunk): TypeError { console.error(thunk); return new TypeError(`Spica: Sequence: Invalid thunk`); } } } function throwCallError(): never { throw new Error(`Spica: Sequence: Invalid thunk call`); }