import { Monad, FunctorFunc, ApplicativeFunc, MonadFunc } from "./interfaces"; /** * Builds a TupleN based on given value length. */ function factory (...values: any[]): any { const tuple = values.slice(0); // [0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8]); Object.defineProperty(tuple, "length", { value: tuple.length }); for (let i = 0, len = tuple.length; i < len; i++) { Object.defineProperty(tuple, `_${i + 1}`, { value: tuple[i] }); } Object.defineProperty(tuple, "equals", { value: function (other: Tuple) { if (this === other) return true; if (! other || "_1" in other === false) return false; if (this.length !== other.length) return false; for (let i = 0; i < this.length; i++) { if (this[i].equals !== undefined && ! this[i].equals(other[i])) { return false; } else if (this[i] !== other[i]) { return false; } } return true; }, }); Object.defineProperty(tuple, "toJSON", { value: function () { return this.slice(0).map((i: any) => !! i && i.toJSON !== undefined ? i.toJSON() : i); }, }); Object.defineProperty(tuple, "toString", { value: function () { return JSON.stringify(this.toJSON()); } }); Object.defineProperty(tuple, "map", { value: function (f: (a: any) => any): Tuple { if (tuple.length === 0) { return TUPLE_ZERO_SINGLETON; } const arr = new Array(tuple.length); for (const i in tuple) { arr[i] = f(tuple[i]); } return factory(...arr); }, }); Object.defineProperty(tuple, "fmap", { value: function (f: (a: any) => Tuple1): Tuple { if (tuple.length === 0) { return TUPLE_ZERO_SINGLETON; } const arr = new Array(tuple.length); for (const i in tuple) { arr[i] = f(tuple[i])[0]; } return factory(...arr); }, }); Object.defineProperty(tuple, "applies", { value: function (f: (a: any) => (b: any) => Tuple1): (tb: Tuple) => Tuple { return function (tb: Tuple): Tuple { if (tuple.length === 0) { return TUPLE_ZERO_SINGLETON; } const arr = new Array(tuple.length); for (const i in tuple) { arr[i] = f(tuple[i])(tb[i])[0]; } return factory(...arr); } }, }); Object.defineProperty(tuple, "mbind", { value: function (f: Array<(a: Tuple) => Tuple>): Tuple { if (tuple.length === 0) { return TUPLE_ZERO_SINGLETON; } const arr = new Array(tuple.length); for (const i in tuple) { arr[i] = f[i](tuple[i])[0]; } return factory(...arr); }, }); return Object.freeze(tuple) as any; } export type TMF = (a: A) => Tuple1; /** * Interface for Tuple extends Array. */ export interface Tuple extends Array { map (callbackfn: (value: any, index?: number, array?: any) => any, thisArg?: any): any; equals (o: Tuple): boolean; toJSON (): any[]; toString (): string; } export interface Tuple0 extends Tuple, Monad { map (f: (a: void) => void): Tuple0; fmap (f: TMF): Tuple0; applies (f: ApplicativeFunc): (mb: Tuple0) => Tuple0; mbind (f: Tuple1>): Tuple0; } export interface Tuple1 extends Tuple, Monad { _1: T1; map (f: (a: T1) => U1): Tuple1; fmap (f: TMF): Tuple1; applies (f: ApplicativeFunc): (mb: Tuple1) => Tuple1; mbind (f: Tuple1>): Tuple1; } export interface Tuple2 extends Tuple, Monad { _1: T1; _2: T2; map (f: (a: T1|T2) => U1|U2): Tuple2; fmap (f: (a: T1|T2) => Tuple1): Tuple2; applies (f: ApplicativeFunc): (mb: Tuple2) => Tuple2; mbind (f: Tuple2, TMF>): Tuple2; } export interface Tuple3 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; map (f: (a: T1|T2|T3) => U1|U2|U3): Tuple3; fmap (f: (a: T1|T2|T3) => Tuple1): Tuple3; applies (f: ApplicativeFunc): (mb: Tuple3) => Tuple3; mbind (f: Tuple3, TMF, TMF>): Tuple3; } export interface Tuple4 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4; map (f: (a: T1|T2|T3|T4) => U1|U2|U3|U4): Tuple4; fmap (f: (a: T1|T2|T3|T4) => Tuple1): Tuple4; applies (f: ApplicativeFunc): (mb: Tuple4) => Tuple4; mbind (f: Tuple4, TMF, TMF, TMF>): Tuple4; } export interface Tuple5 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4; _5: T5; map (f: (a: T1|T2|T3|T4|T5) => U1|U2|U3|U4|U5): Tuple5; fmap (f: (a: T1|T2|T3|T4|T5) => Tuple1): Tuple5; applies (f: ApplicativeFunc): (mb: Tuple5) => Tuple5; mbind (f: Tuple5, TMF, TMF, TMF, TMF>): Tuple5; } export interface Tuple6 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4; _5: T5; _6: T6; map (f: (a: T1|T2|T3|T4|T5|T6) => U1|U2|U3|U4|U5|U6): Tuple6; fmap (f: (a: T1|T2|T3|T4|T5|T6) => Tuple1): Tuple6; applies (f: ApplicativeFunc): (mb: Tuple6) => Tuple6; mbind (f: Tuple6, TMF, TMF, TMF, TMF, TMF>): Tuple6; } export interface Tuple7 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4; _5: T5; _6: T6; _7: T7; map (f: (a: T1|T2|T3|T4|T5|T6|T7) => U1|U2|U3|U4|U5|U6|U7): Tuple7; fmap (f: (a: T1|T2|T3|T4|T5|T6|T7) => Tuple1): Tuple7; applies (f: ApplicativeFunc): (mb: Tuple7) => Tuple7; mbind (f: Tuple7, TMF, TMF, TMF, TMF, TMF, TMF>): Tuple7; } export interface Tuple8 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4, _5: T5; _6: T6; _7: T7; _8: T8; map (f: (a: T1|T2|T3|T4|T5|T6|T7|T8) => U1|U2|U3|U4|U5|U6|U7|U8): Tuple8; fmap (f: (a: T1|T2|T3|T4|T5|T6|T7|T8) => Tuple1): Tuple8; applies (f: ApplicativeFunc): (mb: Tuple8) => Tuple8; mbind (f: Tuple8, TMF, TMF, TMF, TMF, TMF, TMF, TMF>): Tuple8; } export interface Tuple9 extends Tuple, Monad { _1: T1; _2: T2; _3: T3; _4: T4, _5: T5; _6: T6; _7: T7; _8: T8; _9: T9; map (f: (a: T1|T2|T3|T4|T5|T6|T7|T8|T9) => U1|U2|U3|U4|U5|U6|U7|U8|U9): Tuple9; fmap (f: (a: T1|T2|T3|T4|T5|T6|T7|T8|T9) => Tuple1): Tuple9; applies (f: ApplicativeFunc): (mb: Tuple9) => Tuple9; mbind (f: Tuple9, TMF, TMF, TMF, TMF, TMF, TMF, TMF, TMF>): Tuple9; } /** * Tuple0 Singleton. */ const TUPLE_ZERO_SINGLETON = factory(); /** * Namespace for static generators. */ export class Tuples { private constructor () { } static from (): Tuple0 & [void]; static from (_1: T1): Tuple1 & [T1]; static from (_1: T1, _2: T2): Tuple2 & [T1, T2]; static from (_1: T1, _2: T2, _3: T3): Tuple3 & [T1, T2, T3]; static from (_1: T1, _2: T2, _3: T3, _4: T4): Tuple4 & [T1, T2, T3, T4]; static from (_1: T1, _2: T2, _3: T3, _4: T4, _5: T5): Tuple5 & [T1, T2, T3, T4, T5]; static from (_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6): Tuple6 & [T1, T2, T3, T4, T5, T6]; static from (_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7): Tuple7 & [T1, T2, T3, T4, T5, T6, T7]; static from (_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8): Tuple8 & [T1, T2, T3, T4, T5, T6, T7, T8]; static from (_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9): Tuple9 & [T1, T2, T3, T4, T5, T6, T7, T8, T9]; static from (...args: any[]): any { if (args.length === 0) { return TUPLE_ZERO_SINGLETON; } return factory.apply(this, args); } }