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`);
}