"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.findLastIndex = exports.findLast_ = exports.findLast = exports.findIndex_ = exports.findIndex = exports.findFirstMap_ = exports.findFirstMap = exports.findFirst_ = exports.findFirst = exports.collectWhileMap = exports.collectWhileMap_ = exports.filterMapWithIndex_ = exports.filterMapWithIndex = exports.filterMap_ = exports.filterMap = exports.filterWithIndex_ = exports.filterWithIndex = exports.filter_ = exports.filter = exports.extend_ = exports.extend = exports.emptyOf = exports.empty = exports.duplicate = exports.dropRight_ = exports.dropRight = exports.dropLeftWhile_ = exports.dropLeftWhile = exports.dropLeft_ = exports.dropLeft = exports.deleteAt_ = exports.deleteAt = exports.cons = exports.cons_ = exports.concatS = exports.concatS_ = exports.concat = exports.concat_ = exports.comprehension = exports.compact = exports.chunksOf_ = exports.chunksOf = exports.chop_ = exports.chop = exports.tap_ = exports.tap = exports.chain_ = exports.chain = exports.ap_ = exports.ap = void 0;
exports.snoc = exports.snoc_ = exports.scanRight_ = exports.scanRight = exports.scanLeft_ = exports.scanLeft = exports.rotate_ = exports.rotate = exports.rights = exports.reverse = exports.replicate = exports.replicate_ = exports.reduceWithIndex_ = exports.reduceWithIndex = exports.reduceRightWithIndex_ = exports.reduceRightWithIndex = exports.reduceRight_ = exports.reduceRight = exports.reduce_ = exports.reduce = exports.range = exports.single = exports.modifyAt_ = exports.modifyAt = exports.mapWithIndex_ = exports.mapWithIndex = exports.map_ = exports.map = exports.makeBy = exports.makeBy_ = exports.lookup = exports.lookup_ = exports.lefts = exports.last = exports.isOutOfBound = exports.isNonEmpty = exports.isEmpty = exports.insertAt_ = exports.insertAt = exports.init = exports.head = exports.fromMutable = exports.foldRight_ = exports.foldRight = exports.foldLeft_ = exports.foldLeft = exports.flatten = exports.findLastMap_ = exports.findLastMap = exports.findLastIndex_ = void 0;
exports.groupBy_ = exports.groupBy = exports.join = exports.join_ = exports.from = exports.dropWhile = exports.dropWhile_ = exports.separate = exports.zipWith = exports.zipWith_ = exports.zip_ = exports.zip = exports.updateAt_ = exports.updateAt = exports.unzip = exports.unsafeUpdateAt = exports.unsafeUpdateAt_ = exports.unsafeInsertAt = exports.unsafeInsertAt_ = exports.unsafeDeleteAt = exports.unsafeDeleteAt_ = exports.unfold = exports.unfold_ = exports.toMutable = exports.takeRight_ = exports.takeRight = exports.takeUntil_ = exports.takeUntil = exports.takeLeftWhile_ = exports.takeLeftWhile = exports.takeLeft_ = exports.takeLeft = exports.tail = exports.splitAt_ = exports.splitAt = exports.spanLeft_ = exports.spanLeft = exports.spanIndex_ = void 0;
// ets_tracing: off
/**
 * adapted from https://github.com/gcanti/fp-ts
 */
require("../../../Operator");
const core_1 = require("../../../Function/core");
const Option_1 = require("../../../Option");
const Tp = __importStar(require("../Tuple"));
/**
 * Classic Applicative's ap
 */
function ap(fa) {
    return (fab) => ap_(fab, fa);
}
exports.ap = ap;
/**
 * Classic Applicative's ap
 */
function ap_(fab, fa) {
    return flatten(map((f) => map(f)(fa))(fab));
}
exports.ap_ = ap_;
/**
 * Composes computations in sequence, using the return value of one computation to determine the next computation.
 */
function chain(f) {
    return (ma) => chain_(ma, f);
}
exports.chain = chain;
/**
 * Composes computations in sequence, using the return value of one computation to determine the next computation.
 */
function chain_(fa, f) {
    let resLen = 0;
    const l = fa.length;
    const temp = new Array(l);
    for (let i = 0; i < l; i++) {
        const e = fa[i];
        const arr = f(e);
        resLen += arr.length;
        temp[i] = arr;
    }
    const r = Array(resLen);
    let start = 0;
    for (let i = 0; i < l; i++) {
        const arr = temp[i];
        const l = arr.length;
        for (let j = 0; j < l; j++) {
            r[j + start] = arr[j];
        }
        start += l;
    }
    return r;
}
exports.chain_ = chain_;
/**
 * Like chain but ignores output
 */
function tap(f) {
    return (ma) => tap_(ma, f);
}
exports.tap = tap;
/**
 * Like chain but ignores output
 */
function tap_(ma, f) {
    return chain_(ma, (a) => map(() => a)(f(a)));
}
exports.tap_ = tap_;
/**
 * A useful recursion pattern for processing an array to produce a new array, often used for "chopping" up the input
 * array. Typically chop is called with some function that will consume an initial prefix of the array and produce a
 * value and the rest of the array.
 */
function chop(f) {
    return (as) => chop_(as, f);
}
exports.chop = chop;
/**
 * A useful recursion pattern for processing an array to produce a new array, often used for "chopping" up the input
 * array. Typically chop is called with some function that will consume an initial prefix of the array and produce a
 * value and the rest of the array.
 */
function chop_(as, f) {
    const result = [];
    let cs = as;
    while (isNonEmpty(cs)) {
        const { tuple: [b, c] } = f(cs);
        result.push(b);
        cs = c;
    }
    return result;
}
exports.chop_ = chop_;
/**
 * Splits an array into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of
 * the array. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive
 * definition of `chunksOf`; it satisfies the property that
 *
 * ```ts
 * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys)))
 * ```
 *
 * whenever `n` evenly divides the length of `xs`.
 */
function chunksOf(n) {
    return (as) => chunksOf_(as, n);
}
exports.chunksOf = chunksOf;
/**
 * Splits an array into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of
 * the array. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive
 * definition of `chunksOf`; it satisfies the property that
 *
 * ```ts
 * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys)))
 * ```
 *
 * whenever `n` evenly divides the length of `xs`.
 */
function chunksOf_(as, n) {
    const f = chop(splitAt(n));
    return as.length === 0 ? exports.empty : isOutOfBound(n - 1, as) ? [as] : f(as);
}
exports.chunksOf_ = chunksOf_;
/**
 * Filter out optional values
 */
function compact(fa) {
    return (0, exports.filterMap)((x) => x)(fa);
}
exports.compact = compact;
function comprehension(input, f, g = () => true) {
    const go = (scope, input) => {
        if (input.length === 0) {
            return g(...scope) ? [f(...scope)] : exports.empty;
        }
        else {
            return chain((x) => go(snoc_(scope, x), input.slice(1)))(input[0]);
        }
    };
    return go(exports.empty, input);
}
exports.comprehension = comprehension;
/**
 * Concatenate
 */
function concat_(x, y) {
    const lenx = x.length;
    if (lenx === 0) {
        return y;
    }
    const leny = y.length;
    if (leny === 0) {
        return x;
    }
    const r = Array(lenx + leny);
    for (let i = 0; i < lenx; i++) {
        r[i] = x[i];
    }
    for (let i = 0; i < leny; i++) {
        r[i + lenx] = y[i];
    }
    return r;
}
exports.concat_ = concat_;
/**
 * Concatenate
 */
function concat(y) {
    return (x) => concat_(x, y);
}
exports.concat = concat;
/**
 * Concatenate strictly
 */
function concatS_(x, y) {
    return concat_(x, y);
}
exports.concatS_ = concatS_;
/**
 * Concatenate strictly
 */
function concatS(y) {
    return (x) => concatS_(x, y);
}
exports.concatS = concatS;
/**
 * Attaches an element to the front of an array, creating a new non empty array
 *
 * ```ts
 * assert.deepStrictEqual(cons(0, [1, 2, 3]), [0, 1, 2, 3])
 * ```
 */
function cons_(tail, head) {
    const len = tail.length;
    const r = Array(len + 1);
    for (let i = 0; i < len; i++) {
        r[i + 1] = tail[i];
    }
    r[0] = head;
    return r;
}
exports.cons_ = cons_;
/**
 * Attaches an element to the front of an array, creating a new non empty array
 */
function cons(head) {
    return (tail) => cons_(tail, head);
}
exports.cons = cons;
/**
 * Delete the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 *
 * ```ts
 * assert.deepStrictEqual(deleteAt(0)([1, 2, 3]), some([2, 3]))
 * assert.deepStrictEqual(deleteAt(1)([]), none)
 * ```
 */
function deleteAt(i) {
    return (as) => deleteAt_(as, i);
}
exports.deleteAt = deleteAt;
/**
 * Delete the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 */
function deleteAt_(as, i) {
    return isOutOfBound(i, as) ? Option_1.none : (0, Option_1.some)(unsafeDeleteAt_(as, i));
}
exports.deleteAt_ = deleteAt_;
/**
 * Drop a number of elements from the start of an array, creating a new array
 *
 * ```ts
 * assert.deepStrictEqual(dropLeft(2)([1, 2, 3]), [3])
 * ```
 */
function dropLeft(n) {
    return (as) => dropLeft_(as, n);
}
exports.dropLeft = dropLeft;
/**
 * Drop a number of elements from the start of an array, creating a new array
 */
function dropLeft_(as, n) {
    return as.slice(n, as.length);
}
exports.dropLeft_ = dropLeft_;
/**
 * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new array
 *
 * ```ts
 * assert.deepStrictEqual(dropLeftWhile((n: number) => n % 2 === 1)([1, 3, 2, 4, 5]), [2, 4, 5])
 * ```
 */
function dropLeftWhile(predicate) {
    return (as) => dropLeftWhile_(as, predicate);
}
exports.dropLeftWhile = dropLeftWhile;
/**
 * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new array
 *
 * ```
 * assert.deepStrictEqual(dropLeftWhile((n: number) => n % 2 === 1)([1, 3, 2, 4, 5]), [2, 4, 5])
 * ```
 */
function dropLeftWhile_(as, predicate) {
    const i = (0, exports.spanIndex_)(as, predicate);
    const l = as.length;
    const rest = Array(l - i);
    for (let j = i; j < l; j++) {
        rest[j - i] = as[j];
    }
    return rest;
}
exports.dropLeftWhile_ = dropLeftWhile_;
/**
 * Drop a number of elements from the end of an array, creating a new array
 *
 * ```
 * assert.deepStrictEqual(dropRight(2)([1, 2, 3, 4, 5]), [1, 2, 3])
 * ```
 */
function dropRight(n) {
    return (as) => dropRight_(as, n);
}
exports.dropRight = dropRight;
/**
 * Drop a number of elements from the end of an array, creating a new array
 *
 * ```
 * assert.deepStrictEqual(dropRight(2)([1, 2, 3, 4, 5]), [1, 2, 3])
 * ```
 */
function dropRight_(as, n) {
    return as.slice(0, as.length - n);
}
exports.dropRight_ = dropRight_;
/**
 * Array[A] => Array[Array[A]]
 */
function duplicate(ma) {
    return extend((x) => x)(ma);
}
exports.duplicate = duplicate;
/**
 * An empty array
 */
exports.empty = [];
/**
 * An empty array
 */
const emptyOf = () => [];
exports.emptyOf = emptyOf;
/**
 * Extends calls f with all the progressive slices up to the current element's index,
 * and uses the return value to construct the result array
 *
 * i.e: like map that also consumes all the elements up to `i`
 */
function extend(f) {
    return (ma) => extend_(ma, f);
}
exports.extend = extend;
/**
 * Extends calls f with all the progressive slices up to the current element's index,
 * and uses the return value to construct the result array
 *
 * i.e: like map that also consumes all the elements up to `i`
 */
function extend_(ma, f) {
    return ma.map((_, i, as) => f(as.slice(i)));
}
exports.extend_ = extend_;
function filter(predicate) {
    return (fa) => fa.filter(predicate);
}
exports.filter = filter;
function filter_(fa, predicate) {
    return fa.filter(predicate);
}
exports.filter_ = filter_;
/**
 * Filters the array also passing element index
 */
function filterWithIndex(predicate) {
    return (nea) => filterWithIndex_(nea, predicate);
}
exports.filterWithIndex = filterWithIndex;
/**
 * Filters the array also passing element index
 */
function filterWithIndex_(nea, predicate) {
    return nea.filter((a, i) => predicate(i, a));
}
exports.filterWithIndex_ = filterWithIndex_;
/**
 * Filters the array also mapping the output
 */
const filterMap = (f) => (fa) => filterMap_(fa, f);
exports.filterMap = filterMap;
/**
 * Filters the array also mapping the output
 */
function filterMap_(fa, f) {
    return filterMapWithIndex_(fa, (_, a) => f(a));
}
exports.filterMap_ = filterMap_;
/**
 * Filters the array also mapping the output
 */
function filterMapWithIndex(f) {
    return (fa) => filterMapWithIndex_(fa, f);
}
exports.filterMapWithIndex = filterMapWithIndex;
/**
 * Filters the array also mapping the output
 */
function filterMapWithIndex_(fa, f) {
    const result = [];
    for (let i = 0; i < fa.length; i++) {
        const optionB = f(i, fa[i]);
        if ((0, Option_1.isSome)(optionB)) {
            result.push(optionB.value);
        }
    }
    return result;
}
exports.filterMapWithIndex_ = filterMapWithIndex_;
/**
 * Maps an array until `none` is returned
 */
function collectWhileMap_(arr, f) {
    const result = [];
    for (let i = 0; i < arr.length; i++) {
        const o = f(arr[i]);
        if ((0, Option_1.isSome)(o)) {
            result.push(o.value);
        }
        else {
            break;
        }
    }
    return result;
}
exports.collectWhileMap_ = collectWhileMap_;
/**
 * Maps an array until `none` is returned
 */
function collectWhileMap(f) {
    return (arr) => collectWhileMap_(arr, f);
}
exports.collectWhileMap = collectWhileMap;
function findFirst(predicate) {
    return (as) => findFirst_(as, predicate);
}
exports.findFirst = findFirst;
function findFirst_(as, predicate) {
    const len = as.length;
    for (let i = 0; i < len; i++) {
        if (predicate(as[i])) {
            return (0, Option_1.some)(as[i]);
        }
    }
    return Option_1.none;
}
exports.findFirst_ = findFirst_;
/**
 * Find the first element returned by an option based selector function
 *
 * ```ts
 * interface Person {
 *   name: string
 *   age?: number
 * }
 *
 * const persons: Array<Person> = [{ name: 'John' }, { name: 'Mary', age: 45 }, { name: 'Joey', age: 28 }]
 *
 * // returns the name of the first person that has an age
 * assert.deepStrictEqual(findFirstMap((p: Person) => (p.age === undefined ? none : some(p.name)))(persons), some('Mary'))
 * ```
 */
function findFirstMap(f) {
    return (as) => findFirstMap_(as, f);
}
exports.findFirstMap = findFirstMap;
/**
 * Find the first element returned by an option based selector function
 */
function findFirstMap_(as, f) {
    const len = as.length;
    for (let i = 0; i < len; i++) {
        const v = f(as[i]);
        if ((0, Option_1.isSome)(v)) {
            return v;
        }
    }
    return Option_1.none;
}
exports.findFirstMap_ = findFirstMap_;
/**
 * Find the first index for which a predicate holds
 *
 * ```
 * assert.deepStrictEqual(findIndex((n: number) => n === 2)([1, 2, 3]), some(1))
 * assert.deepStrictEqual(findIndex((n: number) => n === 2)([]), none)
 * ```
 */
function findIndex(predicate) {
    return (as) => findIndex_(as, predicate);
}
exports.findIndex = findIndex;
/**
 * Find the first index for which a predicate holds
 */
function findIndex_(as, predicate) {
    const len = as.length;
    for (let i = 0; i < len; i++) {
        if (predicate(as[i])) {
            return (0, Option_1.some)(i);
        }
    }
    return Option_1.none;
}
exports.findIndex_ = findIndex_;
function findLast(predicate) {
    return (as) => findLast_(as, predicate);
}
exports.findLast = findLast;
function findLast_(as, predicate) {
    const len = as.length;
    for (let i = len - 1; i >= 0; i--) {
        if (predicate(as[i])) {
            return (0, Option_1.some)(as[i]);
        }
    }
    return Option_1.none;
}
exports.findLast_ = findLast_;
/**
 * Returns the index of the last element of the list which matches the predicate
 *
 * ```ts
 * interface X {
 *   a: number
 *   b: number
 * }
 * const xs: Array<X> = [{ a: 1, b: 0 }, { a: 1, b: 1 }]
 * assert.deepStrictEqual(findLastIndex((x: { a: number }) => x.a === 1)(xs), some(1))
 * assert.deepStrictEqual(findLastIndex((x: { a: number }) => x.a === 4)(xs), none)
 * ```
 */
function findLastIndex(predicate) {
    return (as) => findLastIndex_(as, predicate);
}
exports.findLastIndex = findLastIndex;
/**
 * Returns the index of the last element of the list which matches the predicate
 */
function findLastIndex_(as, predicate) {
    const len = as.length;
    for (let i = len - 1; i >= 0; i--) {
        if (predicate(as[i])) {
            return (0, Option_1.some)(i);
        }
    }
    return Option_1.none;
}
exports.findLastIndex_ = findLastIndex_;
/**
 * Find the last element returned by an option based selector function
 *
 * ```ts
 * interface Person {
 *   name: string
 *   age?: number
 * }
 *
 * const persons: Array<Person> = [{ name: 'John' }, { name: 'Mary', age: 45 }, { name: 'Joey', age: 28 }]
 *
 * // returns the name of the last person that has an age
 * assert.deepStrictEqual(findLastMap((p: Person) => (p.age === undefined ? none : some(p.name)))(persons), some('Joey'))
 * ```
 */
function findLastMap(f) {
    return (as) => findLastMap_(as, f);
}
exports.findLastMap = findLastMap;
/**
 * Find the last element returned by an option based selector function
 */
function findLastMap_(as, f) {
    const len = as.length;
    for (let i = len - 1; i >= 0; i--) {
        const v = f(as[i]);
        if ((0, Option_1.isSome)(v)) {
            return v;
        }
    }
    return Option_1.none;
}
exports.findLastMap_ = findLastMap_;
/**
 * Removes one level of nesting
 *
 * ```ts
 * assert.deepStrictEqual(flatten([[1], [2], [3]]), [1, 2, 3])
 * ```
 */
function flatten(mma) {
    return chain_(mma, core_1.identity);
}
exports.flatten = flatten;
/**
 * Break an array into its first element and remaining elements
 *
 * ```ts
 * const len: <A>(as: Array<A>) => number = foldLeft(() => 0, (_, tail) => 1 + len(tail))
 * assert.strictEqual(len([1, 2, 3]), 3)
 * ```
 */
function foldLeft(onNil, onCons) {
    return (as) => foldLeft_(as, onNil, onCons);
}
exports.foldLeft = foldLeft;
/**
 * Break an array into its first element and remaining elements
 */
function foldLeft_(as, onNil, onCons) {
    return isEmpty(as) ? onNil() : onCons(as[0], as.slice(1));
}
exports.foldLeft_ = foldLeft_;
/**
 * Break an array into its initial elements and the last element
 */
function foldRight(onNil, onCons) {
    return (as) => foldRight_(as, onNil, onCons);
}
exports.foldRight = foldRight;
/**
 * Break an array into its initial elements and the last element
 */
function foldRight_(as, onNil, onCons) {
    return isEmpty(as) ? onNil() : onCons(as.slice(0, as.length - 1), as[as.length - 1]);
}
exports.foldRight_ = foldRight_;
/**
 * Copies a mutable array into an immutable
 */
function fromMutable(as) {
    const l = as.length;
    if (l === 0) {
        return exports.empty;
    }
    const ras = Array(l);
    for (let i = 0; i < l; i++) {
        ras[i] = as[i];
    }
    return ras;
}
exports.fromMutable = fromMutable;
/**
 * Get the first element in an array, or `None` if the array is empty
 *
 * ```ts
 * assert.deepStrictEqual(head([1, 2, 3]), some(1))
 * assert.deepStrictEqual(head([]), none)
 * ```
 */
function head(as) {
    return isEmpty(as) ? Option_1.none : (0, Option_1.some)(as[0]);
}
exports.head = head;
/**
 * Get all but the last element of an array, creating a new array, or `None` if the array is empty
 *
 * ```
 * assert.deepStrictEqual(init([1, 2, 3]), some([1, 2]))
 * assert.deepStrictEqual(init([]), none)
 * ```
 */
function init(as) {
    const len = as.length;
    return len === 0 ? Option_1.none : (0, Option_1.some)(as.slice(0, len - 1));
}
exports.init = init;
/**
 * Insert an element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 *
 * ```
 * assert.deepStrictEqual(insertAt(2, 5)([1, 2, 3, 4]), some([1, 2, 5, 3, 4]))
 * ```
 */
function insertAt(i, a) {
    return (as) => insertAt_(as, i, a);
}
exports.insertAt = insertAt;
/**
 * Insert an element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 */
function insertAt_(as, i, a) {
    return i < 0 || i > as.length ? Option_1.none : (0, Option_1.some)(unsafeInsertAt_(as, i, a));
}
exports.insertAt_ = insertAt_;
/**
 * Test whether an array is empty
 *
 * ```
 * assert.strictEqual(isEmpty([]), true)
 * ```
 */
function isEmpty(as) {
    return as.length === 0;
}
exports.isEmpty = isEmpty;
/**
 * Test whether an array is non empty narrowing down the type to `NonEmptyArray<A>`
 */
function isNonEmpty(as) {
    return as.length > 0;
}
exports.isNonEmpty = isNonEmpty;
/**
 * Test whether an array contains a particular index
 */
function isOutOfBound(i, as) {
    return i < 0 || i >= as.length;
}
exports.isOutOfBound = isOutOfBound;
/**
 * Get the last element in an array, or `None` if the array is empty
 *
 * ```ts
 * assert.deepStrictEqual(last([1, 2, 3]), some(3))
 * assert.deepStrictEqual(last([]), none)
 * ```
 */
function last(as) {
    return lookup_(as, as.length - 1);
}
exports.last = last;
/**
 * Extracts from an array of `Either` all the `Left` elements. All the `Left` elements are extracted in order
 *
 * ```ts
 * assert.deepStrictEqual(lefts([right(1), left('foo'), right(2)]), ['foo'])
 * ```
 */
function lefts(as) {
    const r = [];
    const len = as.length;
    for (let i = 0; i < len; i++) {
        const a = as[i];
        if (a._tag === "Left") {
            r.push(a.left);
        }
    }
    return r;
}
exports.lefts = lefts;
/**
 * This function provides a safe way to read a value at a particular index from an array
 *
 * ```ts
 * assert.deepStrictEqual(lookup(1, [1, 2, 3]), some(2))
 * assert.deepStrictEqual(lookup(3, [1, 2, 3]), none)
 * ```
 */
function lookup_(as, i) {
    return isOutOfBound(i, as) ? Option_1.none : (0, Option_1.some)(as[i]);
}
exports.lookup_ = lookup_;
/**
 * This function provides a safe way to read a value at a particular index from an array
 */
function lookup(i) {
    return (as) => lookup_(as, i);
}
exports.lookup = lookup;
/**
 * Return a list of length `n` with element `i` initialized with `f(i)`
 *
 * ```ts
 * const double = (n: number): number => n * 2
 * assert.deepStrictEqual(makeBy_(5, double), [0, 2, 4, 6, 8])
 * ```
 */
function makeBy_(n, f) {
    const r = [];
    for (let i = 0; i < n; i++) {
        r.push(f(i));
    }
    return r;
}
exports.makeBy_ = makeBy_;
/**
 * Return a list of length `n` with element `i` initialized with `f(i)`
 */
function makeBy(f) {
    return (n) => makeBy_(n, f);
}
exports.makeBy = makeBy;
/**
 * Apply f to every element of Array<A> returning Array<B>
 */
function map(f) {
    return (fa) => fa.map(f);
}
exports.map = map;
/**
 * Apply f to every element of Array<A> returning Array<B>
 */
function map_(fa, f) {
    return fa.map(f);
}
exports.map_ = map_;
/**
 * Like map but also passes the index to f
 */
function mapWithIndex(f) {
    return (fa) => mapWithIndex_(fa, f);
}
exports.mapWithIndex = mapWithIndex;
/**
 * Like map but also passes the index to f
 */
function mapWithIndex_(fa, f) {
    return fa.map((a, i) => f(i, a));
}
exports.mapWithIndex_ = mapWithIndex_;
/**
 * Apply a function to the element at the specified index, creating a new array, or returning `None` if the index is out
 * of bounds
 *
 * ```ts
 * const double = (x: number): number => x * 2
 * assert.deepStrictEqual(modifyAt(1, double)([1, 2, 3]), some([1, 4, 3]))
 * assert.deepStrictEqual(modifyAt(1, double)([]), none)
 * ```
 */
function modifyAt(i, f) {
    return (as) => (isOutOfBound(i, as) ? Option_1.none : (0, Option_1.some)(unsafeUpdateAt_(as, i, f(as[i]))));
}
exports.modifyAt = modifyAt;
/**
 * Apply a function to the element at the specified index, creating a new array, or returning `None` if the index is out
 * of bounds
 */
function modifyAt_(as, i, f) {
    return isOutOfBound(i, as) ? Option_1.none : (0, Option_1.some)(unsafeUpdateAt_(as, i, f(as[i])));
}
exports.modifyAt_ = modifyAt_;
/**
 * Construct an array with a single element
 */
function single(a) {
    return [a];
}
exports.single = single;
/**
 * Create an array containing a range of integers, including both endpoints
 *
 * ```ts
 * assert.deepStrictEqual(range(1, 5), [1, 2, 3, 4, 5])
 * ```
 */
function range(start, end) {
    return makeBy_(end - start + 1, (i) => start + i);
}
exports.range = range;
/**
 * Construct B by compacting with f over the array from left to right
 */
function reduce(b, f) {
    return (fa) => reduce_(fa, b, f);
}
exports.reduce = reduce;
/**
 * Construct B by compacting with f over the array from left to right
 */
function reduce_(fa, b, f) {
    return reduceWithIndex_(fa, b, (_, b, a) => f(b, a));
}
exports.reduce_ = reduce_;
/**
 * Construct B by compacting with f over the array from right to left
 */
function reduceRight(b, f) {
    return (fa) => reduceRight_(fa, b, f);
}
exports.reduceRight = reduceRight;
/**
 * Construct B by compacting with f over the array from right to left
 */
function reduceRight_(fa, b, f) {
    return reduceRightWithIndex_(fa, b, (_, a, b) => f(a, b));
}
exports.reduceRight_ = reduceRight_;
/**
 * Construct B by compacting with f over the array from right to left
 */
function reduceRightWithIndex(b, f) {
    return (fa) => fa.reduceRight((b, a, i) => f(i, a, b), b);
}
exports.reduceRightWithIndex = reduceRightWithIndex;
/**
 * Construct B by compacting with f over the array from right to left
 */
function reduceRightWithIndex_(fa, b, f) {
    return fa.reduceRight((b, a, i) => f(i, a, b), b);
}
exports.reduceRightWithIndex_ = reduceRightWithIndex_;
/**
 * Construct B by compacting with f over the array from left to right
 */
function reduceWithIndex(b, f) {
    return (fa) => reduceWithIndex_(fa, b, f);
}
exports.reduceWithIndex = reduceWithIndex;
/**
 * Construct B by compacting with f over the array from left to right
 */
function reduceWithIndex_(fa, b, f) {
    const l = fa.length;
    let r = b;
    for (let i = 0; i < l; i++) {
        r = f(i, r, fa[i]);
    }
    return r;
}
exports.reduceWithIndex_ = reduceWithIndex_;
/**
 * Create an array containing a value repeated the specified number of times
 *
 * ```ts
 * assert.deepStrictEqual(replicate_(3, 'a'), ['a', 'a', 'a'])
 * ```
 */
function replicate_(n, a) {
    return makeBy_(n, () => a);
}
exports.replicate_ = replicate_;
/**
 * Create an array containing a value repeated the specified number of times
 *
 * ```ts
 * assert.deepStrictEqual(replicate_(3, 'a'), ['a', 'a', 'a'])
 * ```
 */
function replicate(a) {
    return (n) => replicate_(n, a);
}
exports.replicate = replicate;
/**
 * Reverse an array, creating a new array
 *
 * ```ts
 * assert.deepStrictEqual(reverse([1, 2, 3]), [3, 2, 1])
 * ```
 */
function reverse(as) {
    return [...as].reverse();
}
exports.reverse = reverse;
/**
 * Extracts from an array of `Either` all the `Right` elements. All the `Right` elements are extracted in order
 *
 * ```ts
 * assert.deepStrictEqual(rights([right(1), left('foo'), right(2)]), [1, 2])
 * ```
 */
function rights(as) {
    const r = [];
    const len = as.length;
    for (let i = 0; i < len; i++) {
        const a = as[i];
        if (a._tag === "Right") {
            r.push(a.right);
        }
    }
    return r;
}
exports.rights = rights;
/**
 * Rotate an array to the right by `n` steps
 *
 * ```ts
 * assert.deepStrictEqual(rotate(2)([1, 2, 3, 4, 5]), [4, 5, 1, 2, 3])
 * ```
 */
function rotate(n) {
    return (as) => rotate_(as, n);
}
exports.rotate = rotate;
/**
 * Rotate an array to the right by `n` steps
 */
function rotate_(as, n) {
    const len = as.length;
    if (n === 0 || len <= 1 || len === Math.abs(n)) {
        return as;
    }
    else if (n < 0) {
        return rotate(len + n)(as);
    }
    else {
        return as.slice(-n).concat(as.slice(0, len - n));
    }
}
exports.rotate_ = rotate_;
/**
 * Same as `reduce` but it carries over the intermediate steps
 *
 * ```ts
 * import { scanLeft } from '@matechs/core/Array'
 *
 * assert.deepStrictEqual(scanLeft(10, (b, a: number) => b - a)([1, 2, 3]), [10, 9, 7, 4])
 * ```
 */
function scanLeft(b, f) {
    return (as) => scanLeft_(as, b, f);
}
exports.scanLeft = scanLeft;
/**
 * Same as `reduce` but it carries over the intermediate steps
 */
function scanLeft_(as, b, f) {
    const l = as.length;
    const r = new Array(l + 1);
    r[0] = b;
    for (let i = 0; i < l; i++) {
        r[i + 1] = f(r[i], as[i]);
    }
    return r;
}
exports.scanLeft_ = scanLeft_;
/**
 * Fold an array from the right, keeping all intermediate results instead of only the final result
 *
 * ```ts
 * assert.deepStrictEqual(scanRight(10, (a: number, b) => b - a)([1, 2, 3]), [4, 5, 7, 10])
 * ```
 */
function scanRight(b, f) {
    return (as) => scanRight_(as, b, f);
}
exports.scanRight = scanRight;
/**
 * Fold an array from the right, keeping all intermediate results instead of only the final result
 */
function scanRight_(as, b, f) {
    const l = as.length;
    const r = new Array(l + 1);
    r[l] = b;
    for (let i = l - 1; i >= 0; i--) {
        r[i] = f(as[i], r[i + 1]);
    }
    return r;
}
exports.scanRight_ = scanRight_;
/**
 * Append an element to the end of an array, creating a new non empty array
 *
 * ```ts
 * assert.deepStrictEqual(snoc([1, 2, 3], 4), [1, 2, 3, 4])
 * ```
 */
function snoc_(init, end) {
    const len = init.length;
    const r = Array(len + 1);
    for (let i = 0; i < len; i++) {
        r[i] = init[i];
    }
    r[len] = end;
    return r;
}
exports.snoc_ = snoc_;
/**
 * Append an element to the end of an array, creating a new non empty array
 */
function snoc(end) {
    return (init) => snoc_(init, end);
}
exports.snoc = snoc;
/**
 * Finds the first index that doesn't satisfy predicate or the length of as
 */
const spanIndex_ = (as, predicate) => {
    const l = as.length;
    let i = 0;
    for (; i < l; i++) {
        if (!predicate(as[i])) {
            break;
        }
    }
    return i;
};
exports.spanIndex_ = spanIndex_;
function spanLeft(predicate) {
    return (as) => spanLeft_(as, predicate);
}
exports.spanLeft = spanLeft;
function spanLeft_(as, predicate) {
    const i = (0, exports.spanIndex_)(as, predicate);
    const init = Array(i);
    for (let j = 0; j < i; j++) {
        init[j] = as[j];
    }
    const l = as.length;
    const rest = Array(l - i);
    for (let j = i; j < l; j++) {
        rest[j - i] = as[j];
    }
    return { init, rest };
}
exports.spanLeft_ = spanLeft_;
/**
 * Splits an array into two pieces, the first piece has `n` elements.
 *
 * ```ts
 * assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [[1, 2], [3, 4, 5]])
 * ```
 */
function splitAt(n) {
    return (as) => Tp.tuple(as.slice(0, n), as.slice(n));
}
exports.splitAt = splitAt;
/**
 * Splits an array into two pieces, the first piece has `n` elements.
 */
function splitAt_(as, n) {
    return Tp.tuple(as.slice(0, n), as.slice(n));
}
exports.splitAt_ = splitAt_;
/**
 * Get all but the first element of an array, creating a new array, or `None` if the array is empty
 *
 * ```ts
 * assert.deepStrictEqual(tail([1, 2, 3]), some([2, 3]))
 * assert.deepStrictEqual(tail([]), none)
 * ```
 */
function tail(as) {
    return isEmpty(as) ? Option_1.none : (0, Option_1.some)(as.slice(1));
}
exports.tail = tail;
/**
 * Keep only a number of elements from the start of an array, creating a new array.
 * `n` must be a natural number
 *
 * ```ts
 * assert.deepStrictEqual(takeLeft(2)([1, 2, 3]), [1, 2])
 * ```
 */
function takeLeft(n) {
    return (as) => as.slice(0, n);
}
exports.takeLeft = takeLeft;
/**
 * Keep only a number of elements from the start of an array, creating a new array.
 * `n` must be a natural number
 */
function takeLeft_(as, n) {
    return as.slice(0, n);
}
exports.takeLeft_ = takeLeft_;
function takeLeftWhile(predicate) {
    return (as) => takeLeftWhile_(as, predicate);
}
exports.takeLeftWhile = takeLeftWhile;
function takeLeftWhile_(as, predicate) {
    const i = (0, exports.spanIndex_)(as, predicate);
    const init = Array(i);
    for (let j = 0; j < i; j++) {
        init[j] = as[j];
    }
    return init;
}
exports.takeLeftWhile_ = takeLeftWhile_;
function takeUntil(predicate) {
    return (as) => takeUntil_(as, predicate);
}
exports.takeUntil = takeUntil;
function takeUntil_(as, predicate) {
    const init = [];
    for (let i = 0; i < as.length; i++) {
        init[i] = as[i];
        if (predicate(as[i])) {
            return init;
        }
    }
    return init;
}
exports.takeUntil_ = takeUntil_;
/**
 * Keep only a number of elements from the end of an array, creating a new array.
 * `n` must be a natural number
 *
 * ```ts
 * assert.deepStrictEqual(takeRight(2)([1, 2, 3, 4, 5]), [4, 5])
 * ```
 */
function takeRight(n) {
    return (as) => takeRight_(as, n);
}
exports.takeRight = takeRight;
/**
 * Keep only a number of elements from the end of an array, creating a new array.
 * `n` must be a natural number
 */
function takeRight_(as, n) {
    return n === 0 ? exports.empty : as.slice(-n);
}
exports.takeRight_ = takeRight_;
/**
 * Copies this array into a mutable one
 */
function toMutable(ras) {
    const l = ras.length;
    const as = Array(l);
    for (let i = 0; i < l; i++) {
        as[i] = ras[i];
    }
    return as;
}
exports.toMutable = toMutable;
/**
 * Construct A by unfolding B signaling end with an option
 */
function unfold_(b, f) {
    const ret = [];
    let bb = b;
    // eslint-disable-next-line no-constant-condition
    while (true) {
        const mt = f(bb);
        if ((0, Option_1.isSome)(mt)) {
            const [a, b] = mt.value.tuple;
            ret.push(a);
            bb = b;
        }
        else {
            break;
        }
    }
    return ret;
}
exports.unfold_ = unfold_;
/**
 * Construct A by unfolding B signaling end with an option
 */
function unfold(f) {
    return (b) => unfold_(b, f);
}
exports.unfold = unfold;
/**
 * Deletes index i (non safe)
 */
function unsafeDeleteAt_(as, i) {
    const xs = [...as];
    xs.splice(i, 1);
    return xs;
}
exports.unsafeDeleteAt_ = unsafeDeleteAt_;
/**
 * Deletes index i (non safe)
 */
function unsafeDeleteAt(i) {
    return (as) => unsafeDeleteAt_(as, i);
}
exports.unsafeDeleteAt = unsafeDeleteAt;
/**
 * Inserts index i (non safe)
 */
function unsafeInsertAt_(as, i, a) {
    const xs = [...as];
    xs.splice(i, 0, a);
    return xs;
}
exports.unsafeInsertAt_ = unsafeInsertAt_;
/**
 * Inserts index i (non safe)
 */
function unsafeInsertAt(i, a) {
    return (as) => unsafeInsertAt_(as, i, a);
}
exports.unsafeInsertAt = unsafeInsertAt;
/**
 * Updates index i (non safe)
 */
function unsafeUpdateAt_(as, i, a) {
    if (as[i] === a) {
        return as;
    }
    else {
        const xs = [...as];
        xs[i] = a;
        return xs;
    }
}
exports.unsafeUpdateAt_ = unsafeUpdateAt_;
/**
 * Updates index i (non safe)
 */
function unsafeUpdateAt(i, a) {
    return (as) => unsafeUpdateAt_(as, i, a);
}
exports.unsafeUpdateAt = unsafeUpdateAt;
/**
 * The function is reverse of `zip`. Takes an array of pairs and return two corresponding arrays
 *
 * ```ts
 * assert.deepStrictEqual(unzip([[1, 'a'], [2, 'b'], [3, 'c']]), [[1, 2, 3], ['a', 'b', 'c']])
 * ```
 */
function unzip(as) {
    const fa = [];
    const fb = [];
    for (let i = 0; i < as.length; i++) {
        fa[i] = as[i].get(0);
        fb[i] = as[i].get(1);
    }
    return Tp.tuple(fa, fb);
}
exports.unzip = unzip;
/**
 * Change the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 *
 * ```ts
 * assert.deepStrictEqual(updateAt(1, 1)([1, 2, 3]), some([1, 1, 3]))
 * assert.deepStrictEqual(updateAt(1, 1)([]), none)
 * ```
 */
function updateAt(i, a) {
    return (as) => updateAt_(as, i, a);
}
exports.updateAt = updateAt;
/**
 * Change the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
 */
function updateAt_(as, i, a) {
    return isOutOfBound(i, as) ? Option_1.none : (0, Option_1.some)(unsafeUpdateAt_(as, i, a));
}
exports.updateAt_ = updateAt_;
/**
 * Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
 * longer array are discarded
 *
 * ```ts
 * assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [[1, 'a'], [2, 'b'], [3, 'c']])
 * ```
 */
function zip(fb) {
    return zipWith(fb, Tp.tuple);
}
exports.zip = zip;
/**
 * Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
 * longer array are discarded
 */
function zip_(fa, fb) {
    return zipWith_(fa, fb, Tp.tuple);
}
exports.zip_ = zip_;
/**
 * Apply a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
 * input array is short, excess elements of the longer array are discarded.
 *
 * ```ts
 * assert.deepStrictEqual(zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n), ['a1', 'b2', 'c3'])
 * ```
 */
function zipWith_(fa, fb, f) {
    const fc = [];
    const len = Math.min(fa.length, fb.length);
    for (let i = 0; i < len; i++) {
        fc[i] = f(fa[i], fb[i]);
    }
    return fc;
}
exports.zipWith_ = zipWith_;
/**
 * Apply a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
 * input array is short, excess elements of the longer array are discarded.
 */
function zipWith(fb, f) {
    return (fa) => zipWith_(fa, fb, f);
}
exports.zipWith = zipWith;
/**
 * Separate Array
 */
function separate(fa) {
    const left = [];
    const right = [];
    for (const e of fa) {
        if (e._tag === "Left") {
            left.push(e.left);
        }
        else {
            right.push(e.right);
        }
    }
    return {
        left,
        right
    };
}
exports.separate = separate;
/**
 * Drops elements while the predicate returns true
 */
function dropWhile_(as, predicate) {
    const i = (0, exports.spanIndex_)(as, predicate);
    const l = as.length;
    const rest = Array(l - i);
    for (let j = i; j < l; j++) {
        rest[j - i] = as[j];
    }
    return rest;
}
exports.dropWhile_ = dropWhile_;
/**
 * Drops elements while the predicate returns true
 */
function dropWhile(predicate) {
    return (as) => dropWhile_(as, predicate);
}
exports.dropWhile = dropWhile;
/**
 * Constructs a new readonly array from an interable.
 */
function from(as) {
    return Array.from(as);
}
exports.from = from;
/**
 * Joins together string arrays
 */
function join_(as, s) {
    return as.join(s);
}
exports.join_ = join_;
/**
 * Joins together string arrays
 */
function join(s) {
    return (as) => as.join(s);
}
exports.join = join;
/**
 * Splits an array into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning
 * function on each element, and grouping the results according to values returned
 */
function groupBy(f) {
    return (as) => groupBy_(as, f);
}
exports.groupBy = groupBy;
/**
 * Splits an array into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning
 * function on each element, and grouping the results according to values returned
 */
function groupBy_(as, f) {
    const r = {};
    for (const a of as) {
        const k = f(a);
        // eslint-disable-next-line no-prototype-builtins
        if (r.hasOwnProperty(k)) {
            r[k].push(a);
        }
        else {
            r[k] = [a];
        }
    }
    return r;
}
exports.groupBy_ = groupBy_;
//# sourceMappingURL=index.js.map