/** * This module provides utility functions for working with arrays in TypeScript. * * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import { dual, identity } from "@fp-ts/core/Function" import type { LazyArg } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import * as string from "@fp-ts/core/String" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import * as order from "@fp-ts/core/typeclass/Order" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as pointed from "@fp-ts/core/typeclass/Pointed" import type * as product_ from "@fp-ts/core/typeclass/Product" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" /** * @category type lambdas * @since 1.0.0 */ export interface ReadonlyArrayTypeLambda extends TypeLambda { readonly type: ReadonlyArray } /** * @category models * @since 1.0.0 */ export type NonEmptyReadonlyArray = readonly [A, ...Array] /** * @category models * @since 1.0.0 */ export type NonEmptyArray = [A, ...Array] /** * Builds a `NonEmptyArray` from an non-empty collection of elements. * * @category constructors * @since 1.0.0 */ export const make = >( ...elements: Elements ): NonEmptyArray => elements /** * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. * * **Note**. `n` is normalized to an integer >= 1. * * @example * import { makeBy } from '@fp-ts/core/ReadonlyArray' * * assert.deepStrictEqual(makeBy(5, n => n * 2), [0, 2, 4, 6, 8]) * * @category constructors * @since 1.0.0 */ export const makeBy = (n: number, f: (i: number) => A): NonEmptyArray => { const max = Math.max(1, Math.floor(n)) const out: NonEmptyArray = [f(0)] for (let i = 1; i < max; i++) { out.push(f(i)) } return out } /** * Return a `NonEmptyArray` containing a range of integers, including both endpoints. * * @example * import { range } from '@fp-ts/core/ReadonlyArray' * * assert.deepStrictEqual(range(1, 3), [1, 2, 3]) * * @category constructors * @since 1.0.0 */ export const range = (start: number, end: number): NonEmptyArray => start <= end ? makeBy(end - start + 1, (i) => start + i) : [start] /** * Return a `NonEmptyArray` containing a value repeated the specified number of times. * * **Note**. `n` is normalized to an integer >= 1. * * @example * import { replicate } from '@fp-ts/core/ReadonlyArray' * * assert.deepStrictEqual(replicate("a", 3), ["a", "a", "a"]) * * @category constructors * @since 1.0.0 */ export const replicate: { (n: number): (a: A) => NonEmptyArray (a: A, n: number): NonEmptyArray } = dual(2, (a: A, n: number): NonEmptyArray => makeBy(n, () => a)) /** * @category conversions * @since 1.0.0 */ export const fromIterable: (collection: Iterable) => Array = readonlyArray.fromIterable /** * @category conversions * @since 1.0.0 */ export const fromOption: (self: Option) => Array = O.toArray /** * @category conversions * @since 1.0.0 */ export const fromEither: (self: Either) => Array = E.toArray /** * @category pattern matching * @since 1.0.0 */ export const match: { ( onEmpty: LazyArg, onNonEmpty: (self: NonEmptyReadonlyArray) => C ): (self: ReadonlyArray) => B | C ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (self: NonEmptyReadonlyArray) => C ): B | C } = dual(3, ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (self: NonEmptyReadonlyArray) => C ): B | C => isNonEmpty(self) ? onNonEmpty(self) : onEmpty()) /** * @category pattern matching * @since 1.0.0 */ export const matchLeft: { ( onEmpty: LazyArg, onNonEmpty: (head: A, tail: Array) => C ): (self: ReadonlyArray) => B | C ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (head: A, tail: Array) => C ): B | C } = dual(3, ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (head: A, tail: Array) => C ): B | C => isNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty()) /** * @category pattern matching * @since 1.0.0 */ export const matchRight: { ( onEmpty: LazyArg, onNonEmpty: (init: Array, last: A) => C ): (self: ReadonlyArray) => B | C ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (init: Array, last: A) => C ): B | C } = dual(3, ( self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (init: Array, last: A) => C ): B | C => isNonEmpty(self) ? onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : onEmpty()) /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. * * @since 1.0.0 */ export const prepend: { (head: B): (self: Iterable) => NonEmptyArray (self: Iterable, head: B): NonEmptyArray } = dual(2, (self: Iterable, head: B): NonEmptyArray => [head, ...self]) /** * @since 1.0.0 */ export const prependAll: { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } = dual( 2, (self: Iterable, that: Iterable): Array => fromIterable(that).concat(fromIterable(self)) ) /** * @since 1.0.0 */ export const prependAllNonEmpty: { (that: NonEmptyReadonlyArray): (self: Iterable) => NonEmptyArray (that: Iterable): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray } = dual( 2, (self: Iterable, that: Iterable): Array => prependAll(self, that) ) /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. * * @since 1.0.0 */ export const append: { (last: B): (self: Iterable) => NonEmptyArray (self: Iterable, last: B): NonEmptyArray } = dual(2, (self: Iterable, last: B): Array => [...self, last]) /** * @since 1.0.0 */ export const appendAll: { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } = dual( 2, (self: Iterable, that: Iterable): Array => fromIterable(self).concat(fromIterable(that)) ) /** * @since 1.0.0 */ export const appendAllNonEmpty: { (that: NonEmptyReadonlyArray): (self: Iterable) => NonEmptyArray (that: Iterable): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray } = dual( 2, (self: Iterable, that: Iterable): Array => appendAll(self, that) ) /** * Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. * * @category folding * @since 1.0.0 */ export const scan: { (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray } = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { const out: NonEmptyArray = [b] let i = 0 for (const a of self) { out[i + 1] = f(out[i], a) i++ } return out }) /** * Reduce an `Iterable` from the right, keeping all intermediate results instead of only the final result. * * @category folding * @since 1.0.0 */ export const scanRight: { (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray } = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { const input = fromIterable(self) const out: NonEmptyArray = new Array(input.length + 1) as any out[input.length] = b for (let i = input.length - 1; i >= 0; i--) { out[i] = f(out[i + 1], input[i]) } return out }) /** * Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. * * @param self - The `ReadonlyArray` to check. * * @example * import { isEmpty } from "@fp-ts/core/ReadonlyArray" * * assert.deepStrictEqual(isEmpty([]), true); * assert.deepStrictEqual(isEmpty([1, 2, 3]), false); * * @category guards * @since 1.0.0 */ export function isEmpty(self: Array): self is [] export function isEmpty(self: ReadonlyArray): self is readonly [] export function isEmpty(self: ReadonlyArray): self is readonly [] { return self.length === 0 } /** * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyArray`. * * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. * * @param self - The `ReadonlyArray` to check. * * @example * import { isNonEmpty } from "@fp-ts/core/ReadonlyArray" * * assert.deepStrictEqual(isNonEmpty([]), false); * assert.deepStrictEqual(isNonEmpty([1, 2, 3]), true); * * @category guards * @since 1.0.0 */ export const isNonEmpty: { (self: Array): self is NonEmptyArray (self: ReadonlyArray): self is NonEmptyReadonlyArray } = readonlyArray.isNonEmpty /** * Return the number of elements in a `ReadonlyArray`. * * @category getters * @since 1.0.0 */ export const length = (self: ReadonlyArray): number => self.length const isOutOfBound = (i: number, as: ReadonlyArray): boolean => i < 0 || i >= as.length const clamp = (i: number, as: ReadonlyArray): number => Math.floor(Math.min(Math.max(0, i), as.length)) /** * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. * * @category getters * @since 1.0.0 */ export const get: { (index: number): (self: ReadonlyArray) => Option (self: ReadonlyArray, index: number): Option } = dual(2, (self: ReadonlyArray, index: number): Option => { const i = Math.floor(index) return isOutOfBound(i, self) ? O.none() : O.some(self[i]) }) /** * Gets an element unsafely, will throw on out of bounds. * * @since 1.0.0 * @category unsafe */ export const unsafeGet: { (index: number): (self: ReadonlyArray) => A (self: ReadonlyArray, index: number): A } = dual(2, (self: ReadonlyArray, index: number): A => { const i = Math.floor(index) if (isOutOfBound(i, self)) { throw new Error(`Index ${i} out of bounds`) } return self[i] }) /** * Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. * * @category getters * @since 1.0.0 */ export const unprepend = ( self: NonEmptyReadonlyArray ): [A, Array] => [headNonEmpty(self), tailNonEmpty(self)] /** * Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element. * * @category getters * @since 1.0.0 */ export const unappend = ( self: NonEmptyReadonlyArray ): [Array, A] => [initNonEmpty(self), lastNonEmpty(self)] /** * Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. * * @category getters * @since 1.0.0 */ export const head: (self: ReadonlyArray) => Option = get(0) /** * @category getters * @since 1.0.0 */ export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = unsafeGet(0) /** * Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. * * @category getters * @since 1.0.0 */ export const last = (self: ReadonlyArray): Option => isNonEmpty(self) ? O.some(lastNonEmpty(self)) : O.none() /** * @category getters * @since 1.0.0 */ export const lastNonEmpty = (self: NonEmptyReadonlyArray): A => self[self.length - 1] /** * Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. * * @category getters * @since 1.0.0 */ export const tail = (self: Iterable): Option> => { const input = fromIterable(self) return isNonEmpty(input) ? O.some(tailNonEmpty(input)) : O.none() } /** * @category getters * @since 1.0.0 */ export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(1) /** * Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. * * @category getters * @since 1.0.0 */ export const init = (self: Iterable): Option> => { const input = fromIterable(self) return isNonEmpty(input) ? O.some(initNonEmpty(input)) : O.none() } /** * Get all but the last element of a non empty array, creating a new array. * * @category getters * @since 1.0.0 */ export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(0, -1) /** * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * @category getters * @since 1.0.0 */ export const take: { (n: number): (self: Iterable) => Array (self: Iterable, n: number): Array } = dual(2, (self: Iterable, n: number): Array => { const input = fromIterable(self) return input.slice(0, clamp(n, input)) }) /** * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * @category getters * @since 1.0.0 */ export const takeRight: { (n: number): (self: Iterable) => Array (self: Iterable, n: number): Array } = dual(2, (self: Iterable, n: number): Array => { const input = fromIterable(self) const i = clamp(n, input) return i === 0 ? [] : input.slice(-i) }) /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * @category getters * @since 1.0.0 */ export const takeWhile: { (refinement: Refinement): (self: Iterable) => Array (predicate: Predicate): (self: Iterable) => Array (self: Iterable, refinement: Refinement): Array (self: Iterable, predicate: Predicate): Array } = dual(2, (self: Iterable, predicate: Predicate): Array => { const out: Array = [] for (const a of self) { if (!predicate(a)) { break } out.push(a) } return out }) const spanIndex = (self: Iterable, predicate: Predicate): number => { let i = 0 for (const a of self) { if (!predicate(a)) { break } i++ } return i } /** * Split an `Iterable` into two parts: * * 1. the longest initial subarray for which all elements satisfy the specified predicate * 2. the remaining elements * * @category filtering * @since 1.0.0 */ export const span: { ( refinement: Refinement ): (self: Iterable) => [init: Array, rest: Array] (predicate: Predicate): (self: Iterable) => [init: Array, rest: Array] ( self: Iterable, refinement: Refinement ): [init: Array, rest: Array] (self: Iterable, predicate: Predicate): [init: Array, rest: Array] } = dual( 2, (self: Iterable, predicate: Predicate): [init: Array, rest: Array] => splitAt(self, spanIndex(self, predicate)) ) /** * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * @category getters * @since 1.0.0 */ export const drop: { (n: number): (self: Iterable) => Array (self: Iterable, n: number): Array } = dual(2, (self: Iterable, n: number): Array => { const input = fromIterable(self) return input.slice(clamp(n, input), input.length) }) /** * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. * * **Note**. `n` is normalized to a non negative integer. * * @category getters * @since 1.0.0 */ export const dropRight: { (n: number): (self: Iterable) => Array (self: Iterable, n: number): Array } = dual(2, (self: Iterable, n: number): Array => { const input = fromIterable(self) return input.slice(0, input.length - clamp(n, input)) }) /** * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. * * @category getters * @since 1.0.0 */ export const dropWhile: { (refinement: Refinement): (self: Iterable) => Array (predicate: Predicate): (self: Iterable) => Array (self: Iterable, refinement: Refinement): Array (self: Iterable, predicate: Predicate): Array } = dual( 2, (self: Iterable, predicate: Predicate): Array => fromIterable(self).slice(spanIndex(self, predicate)) ) /** * Return the first index for which a predicate holds. * * @category getters * @since 1.0.0 */ export const findFirstIndex: { (predicate: Predicate): (self: Iterable) => Option (self: Iterable, predicate: Predicate): Option } = dual(2, (self: Iterable, predicate: Predicate): Option => { let i = 0 for (const a of self) { if (predicate(a)) { return O.some(i) } i++ } return O.none() }) /** * Return the last index for which a predicate holds. * * @category getters * @since 1.0.0 */ export const findLastIndex: { (predicate: Predicate): (self: Iterable) => Option (self: Iterable, predicate: Predicate): Option } = dual(2, (self: Iterable, predicate: Predicate): Option => { const input = fromIterable(self) for (let i = input.length - 1; i >= 0; i--) { if (predicate(input[i])) { return O.some(i) } } return O.none() }) /** * Find the first element for which a predicate holds. * * @category getters * @since 1.0.0 */ export const findFirst: { (refinement: Refinement): (self: Iterable) => Option (predicate: Predicate): (self: Iterable) => Option (self: Iterable, refinement: Refinement): Option (self: Iterable, predicate: Predicate): Option } = dual(2, (self: Iterable, predicate: Predicate): Option => { const input = fromIterable(self) for (let i = 0; i < input.length; i++) { if (predicate(input[i])) { return O.some(input[i]) } } return O.none() }) /** * Find the last element for which a predicate holds. * * @category getters * @since 1.0.0 */ export const findLast: { (refinement: Refinement): (self: Iterable) => Option (predicate: Predicate): (self: Iterable) => Option (self: Iterable, refinement: Refinement): Option (self: Iterable, predicate: Predicate): Option } = dual(2, (self: Iterable, predicate: Predicate): Option => { const input = fromIterable(self) for (let i = input.length - 1; i >= 0; i--) { if (predicate(input[i])) { return O.some(input[i]) } } return O.none() }) /** * Insert an element at the specified index, creating a new `NonEmptyArray`, * or return `None` if the index is out of bounds. * * @since 1.0.0 */ export const insertAt: { (i: number, b: B): (self: Iterable) => Option> (self: Iterable, i: number, b: B): Option> } = dual(3, (self: Iterable, i: number, b: B): Option> => { const out: Array = Array.from(self) // v--- `= self.length` is ok, it means inserting in last position if (i < 0 || i > out.length) { return O.none() } out.splice(i, 0, b) return O.some(out) as any }) /** * Change the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * * @since 1.0.0 */ export const replace: { (i: number, b: B): (self: Iterable) => Array (self: Iterable, i: number, b: B): Array } = dual(3, (self: Iterable, i: number, b: B): Array => modify(self, i, () => b)) /** * @since 1.0.0 */ export const replaceOption: { (i: number, b: B): (self: Iterable) => Option> (self: Iterable, i: number, b: B): Option> } = dual( 3, (self: Iterable, i: number, b: B): Option> => modifyOption(self, i, () => b) ) /** * Apply a function to the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * * @since 1.0.0 */ export const modify: { (i: number, f: (a: A) => B): (self: Iterable) => Array (self: Iterable, i: number, f: (a: A) => B): Array } = dual( 3, (self: Iterable, i: number, f: (a: A) => B): Array => O.getOrElse(modifyOption(self, i, f), () => Array.from(self)) ) /** * Apply a function to the element at the specified index, creating a new `Array`, * or return `None` if the index is out of bounds. * * @since 1.0.0 */ export const modifyOption: { (i: number, f: (a: A) => B): (self: Iterable) => Option> (self: Iterable, i: number, f: (a: A) => B): Option> } = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option> => { const out = Array.from(self) if (isOutOfBound(i, out)) { return O.none() } const next = f(out[i]) // @ts-expect-error out[i] = next return O.some(out) }) /** * Delete the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * * @since 1.0.0 */ export const remove: { (i: number): (self: Iterable) => Array (self: Iterable, i: number): Array } = dual(2, (self: Iterable, i: number): Array => { const out = Array.from(self) if (isOutOfBound(i, out)) { return out } out.splice(i, 1) return out }) /** * Reverse an `Iterable`, creating a new `Array`. * * @since 1.0.0 */ export const reverse = (self: Iterable): Array => Array.from(self).reverse() /** * @since 1.0.0 */ export const reverseNonEmpty = ( self: NonEmptyReadonlyArray ): NonEmptyArray => [lastNonEmpty(self), ...self.slice(0, -1).reverse()] /** * Return all the `Right` elements from an `Interable` of `Either`s. * * @category getters * @since 1.0.0 */ export const rights: (self: Iterable>) => Array = E.rights /** * Return all the `Left` elements from an `Interable` of `Either`s. * * @category getters * @since 1.0.0 */ export const lefts: (self: Iterable>) => Array = E.lefts /** * Sort the elements of an `Iterable` in increasing order, creating a new `Array`. * * @category sorting * @since 1.0.0 */ export const sort = (O: Order) => (self: Iterable): Array => { const out = Array.from(self) out.sort(O.compare) return out } /** * Sort the elements of a `NonEmptyReadonlyArray` in increasing order, creating a new `NonEmptyArray`. * * @category sorting * @since 1.0.0 */ export const sortNonEmpty = (O: Order) => (self: NonEmptyReadonlyArray): NonEmptyArray => sort(O)(self) as any /** * Sort the elements of an `Iterable` in increasing order, where elements are compared * using first `orders[0]`, then `orders[1]`, etc... * * @category sorting * @since 1.0.0 */ export const sortBy = (...orders: ReadonlyArray>) => (self: Iterable): Array => { const input = fromIterable(self) return (isNonEmpty(input) ? sortByNonEmpty(...orders)(input) : []) } /** * @category sorting * @since 1.0.0 */ export const sortByNonEmpty = ( ...orders: ReadonlyArray> ): ((as: NonEmptyReadonlyArray) => NonEmptyArray) => sortNonEmpty(order.getMonoid().combineAll(orders)) /** * Takes two `Iterable`s and returns an `Array` of corresponding pairs. * If one input `Iterable` is short, excess elements of the * longer `Iterable` are discarded. * * @since 1.0.0 */ export const zip: { (that: Iterable): (self: Iterable) => Array<[A, B]> (self: Iterable, that: Iterable): Array<[A, B]> } = dual( 2, (self: Iterable, that: Iterable): Array<[A, B]> => zipWith(self, that, (a, b) => [a, b]) ) /** * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. * * @since 1.0.0 */ export const zipWith: { (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Array (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array } = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array => { const as = fromIterable(self) const bs = fromIterable(that) return isNonEmpty(as) && isNonEmpty(bs) ? zipNonEmptyWith(bs, f)(as) : [] }) /** * @since 1.0.0 */ export const zipNonEmpty: { (that: NonEmptyReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray<[A, B]> (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> } = dual( 2, (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => zipNonEmptyWith(self, that, (a, b) => [a, b]) ) /** * @since 1.0.0 */ export const zipNonEmptyWith: { ( that: NonEmptyReadonlyArray, f: (a: A, b: B) => C ): (self: NonEmptyReadonlyArray) => NonEmptyArray ( self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray, f: (a: A, b: B) => C ): NonEmptyArray } = dual(3, ( self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray, f: (a: A, b: B) => C ): NonEmptyArray => { const cs: NonEmptyArray = [f(headNonEmpty(self), headNonEmpty(that))] const len = Math.min(self.length, that.length) for (let i = 1; i < len; i++) { cs[i] = f(self[i], that[i]) } return cs }) /** * This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. * * @since 1.0.0 */ export const unzip = (self: Iterable<[A, B]>): [Array, Array] => { const input = fromIterable(self) return isNonEmpty(input) ? unzipNonEmpty(input) : [[], []] } /** * @since 1.0.0 */ export const unzipNonEmpty = ( self: NonEmptyReadonlyArray<[A, B]> ): [NonEmptyArray, NonEmptyArray] => { const fa: NonEmptyArray = [self[0][0]] const fb: NonEmptyArray = [self[0][1]] for (let i = 1; i < self.length; i++) { fa[i] = self[i][0] fb[i] = self[i][1] } return [fa, fb] } /** * Places an element in between members of an `Iterable` * * @since 1.0.0 */ export const intersperse: { (middle: B): (self: Iterable) => Array (self: Iterable, middle: B): Array } = dual(2, (self: Iterable, middle: B): Array => { const input = fromIterable(self) return (isNonEmpty(input) ? intersperseNonEmpty(input, middle) : []) }) /** * Places an element in between members of a `NonEmptyReadonlyArray` * * @since 1.0.0 */ export const intersperseNonEmpty: { (middle: B): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray } = dual(2, (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray => { const out: NonEmptyArray = [headNonEmpty(self)] const tail = tailNonEmpty(self) for (let i = 0; i < tail.length; i++) { if (i < tail.length) { out.push(middle) } out.push(tail[i]) } return out }) /** * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ export const modifyNonEmptyHead: { (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray } = dual( 2, ( self: NonEmptyReadonlyArray, f: (a: A) => B ): NonEmptyArray => [f(headNonEmpty(self)), ...tailNonEmpty(self)] ) /** * Change the head, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ export const setNonEmptyHead: { (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, b: B): NonEmptyArray } = dual( 2, (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyNonEmptyHead(self, () => b) ) /** * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ export const modifyNonEmptyLast: { (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray } = dual( 2, (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => append(initNonEmpty(self), f(lastNonEmpty(self))) ) /** * Change the last element, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ export const setNonEmptyLast: { (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, b: B): NonEmptyArray } = dual( 2, (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyNonEmptyLast(self, () => b) ) /** * Rotate an `Iterable` by `n` steps. * * @since 1.0.0 */ export const rotate: { (n: number): (self: Iterable) => Array (self: Iterable, n: number): Array } = dual(2, (self: Iterable, n: number): Array => { const input = fromIterable(self) return isNonEmpty(input) ? rotateNonEmpty(input, n) : [] }) /** * Rotate a `NonEmptyReadonlyArray` by `n` steps. * * @since 1.0.0 */ export const rotateNonEmpty: { (n: number): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: NonEmptyReadonlyArray, n: number): NonEmptyArray } = dual(2, (self: NonEmptyReadonlyArray, n: number): NonEmptyArray => { const len = self.length const m = Math.round(n) % len if (isOutOfBound(Math.abs(m), self) || m === 0) { return copy(self) } if (m < 0) { const [f, s] = splitNonEmptyAt(self, -m) return appendAllNonEmpty(s, f) } else { return rotateNonEmpty(self, m - len) } }) /** * Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. * * @category predicates * @since 1.0.0 */ export const contains = (isEquivalent: (self: A, that: A) => boolean): { (a: A): (self: Iterable) => boolean (self: Iterable, a: A): boolean } => dual(2, (self: Iterable, a: A): boolean => { for (const i of self) { if (isEquivalent(a, i)) { return true } } return false }) /** * Remove duplicates from am `Iterable`, keeping the first occurrence of an element. * * @since 1.0.0 */ export const uniq = (isEquivalent: (self: A, that: A) => boolean) => (self: Iterable): Array => { const input = fromIterable(self) return isNonEmpty(input) ? uniqNonEmpty(isEquivalent)(input) : [] } /** * Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence of an element. * * @since 1.0.0 */ export const uniqNonEmpty = (isEquivalent: (self: A, that: A) => boolean) => (self: NonEmptyReadonlyArray): NonEmptyArray => { const out: NonEmptyArray = [headNonEmpty(self)] const rest = tailNonEmpty(self) for (const a of rest) { if (out.every((o) => !isEquivalent(a, o))) { out.push(a) } } return out } /** * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a * value and the rest of the `Array`. * * @since 1.0.0 */ export const chop: { ( f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): (self: Iterable) => Array ( self: Iterable, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): Array } = dual(2, ( self: Iterable, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): Array => { const input = fromIterable(self) return isNonEmpty(input) ? chopNonEmpty(input, f) : [] }) /** * A useful recursion pattern for processing a `NonEmptyReadonlyArray` to produce a new `NonEmptyReadonlyArray`, often used for "chopping" up the input * `NonEmptyReadonlyArray`. Typically `chop` is called with some function that will consume an initial prefix of the `NonEmptyReadonlyArray` and produce a * value and the tail of the `NonEmptyReadonlyArray`. * * @since 1.0.0 */ export const chopNonEmpty: { ( f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): (self: NonEmptyReadonlyArray) => NonEmptyArray ( self: NonEmptyReadonlyArray, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): NonEmptyArray } = dual(2, ( self: NonEmptyReadonlyArray, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] ): NonEmptyArray => { const [b, rest] = f(self) const out: NonEmptyArray = [b] let next: ReadonlyArray = rest while (readonlyArray.isNonEmpty(next)) { const [b, rest] = f(next) out.push(b) next = rest } return out }) /** * Splits an `Iterable` into two pieces, the first piece has max `n` elements. * * @category getters * @since 1.0.0 */ export const splitAt: { (n: number): (self: Iterable) => [Array, Array] (self: Iterable, n: number): [Array, Array] } = dual(2, (self: Iterable, n: number): [Array, Array] => { const input = Array.from(self) return n >= 1 && isNonEmpty(input) ? splitNonEmptyAt(input, n) : isEmpty(input) ? [input, []] : [[], input] }) /** * @since 1.0.0 */ export const copy: { (self: NonEmptyReadonlyArray): NonEmptyArray (self: ReadonlyArray): Array } = ((self: ReadonlyArray): Array => self.slice()) as any /** * Splits a `NonEmptyReadonlyArray` into two pieces, the first piece has max `n` elements. * * @category getters * @since 1.0.0 */ export const splitNonEmptyAt: { (n: number): (self: NonEmptyReadonlyArray) => [NonEmptyArray, Array] (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] } = dual(2, (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] => { const m = Math.max(1, n) return m >= self.length ? [copy(self), []] : [prepend(self.slice(1, m), headNonEmpty(self)), self.slice(m)] }) /** * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of * the `Iterable`. 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 `self`. * * @category getters * @since 1.0.0 */ export const chunksOf: { (n: number): (self: Iterable) => Array> (self: Iterable, n: number): Array> } = dual(2, (self: Iterable, n: number): Array> => { const input = fromIterable(self) return isNonEmpty(input) ? chunksOfNonEmpty(input, n) : [] }) /** * Splits a `NonEmptyReadonlyArray` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of * the `NonEmptyReadonlyArray`. * * @category getters * @since 1.0.0 */ export const chunksOfNonEmpty: { (n: number): (self: NonEmptyReadonlyArray) => NonEmptyArray> (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> } = dual( 2, (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> => chopNonEmpty(self, splitNonEmptyAt(n)) ) /** * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s. * * @category grouping * @since 1.0.0 */ export const group = (isEquivalent: (self: A, that: A) => boolean) => (self: NonEmptyReadonlyArray): NonEmptyArray> => chopNonEmpty(self, (as) => { const h = headNonEmpty(as) const out: NonEmptyArray = [h] let i = 1 for (; i < as.length; i++) { const a = as[i] if (isEquivalent(a, h)) { out.push(a) } else { break } } return [out, as.slice(i)] }) /** * Splits an `Iterable` 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 * * @category grouping * @since 1.0.0 */ export const groupBy: { (f: (a: A) => string): (self: Iterable) => Record> (self: Iterable, f: (a: A) => string): Record> } = dual(2, (self: Iterable, f: (a: A) => string): Record> => { const out: Record> = {} for (const a of self) { const k = f(a) if (Object.prototype.hasOwnProperty.call(out, k)) { out[k].push(a) } else { out[k] = [a] } } return out }) /** * @since 1.0.0 */ export const union = (isEquivalent: (self: A, that: A) => boolean): { (that: ReadonlyArray): (self: ReadonlyArray) => Array (self: ReadonlyArray, that: ReadonlyArray): Array } => dual(2, (self: ReadonlyArray, that: ReadonlyArray): Array => { const a = Array.from(self) const b = Array.from(that) return isNonEmpty(a) && isNonEmpty(b) ? unionNonEmpty(isEquivalent)(a, b) : isNonEmpty(a) ? a : b }) /** * @since 1.0.0 */ export const unionNonEmpty = (isEquivalent: (self: A, that: A) => boolean): { (that: NonEmptyReadonlyArray): (self: ReadonlyArray) => NonEmptyArray (that: ReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: ReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray } => dual( 2, (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray => uniqNonEmpty(isEquivalent)(appendAllNonEmpty(self, that)) ) /** * Creates an `Array` of unique values that are included in all given `Iterable`s. * The order and references of result values are determined by the first `Iterable`. * * @since 1.0.0 */ export const intersection = (isEquivalent: (self: A, that: A) => boolean): { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } => { const has = contains(isEquivalent) return dual( 2, (self: Iterable, that: Iterable): Array => fromIterable(self).filter((a) => has(that, a)) ) } /** * Creates a `Array` of values not included in the other given `Iterable`. * The order and references of result values are determined by the first `Iterable`. * * @since 1.0.0 */ export const difference = (isEquivalent: (self: A, that: A) => boolean): { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } => { const has = contains(isEquivalent) return dual( 2, (self: Iterable, that: Iterable): Array => fromIterable(self).filter((a) => !has(that, a)) ) } /** * @category constructors * @since 1.0.0 */ export const of = (a: A): NonEmptyArray => [a] /** * @category constructors * @since 1.0.0 */ export const empty: () => Array = () => [] /** * @category instances * @since 1.0.0 */ export const Of: of_.Of = { of } /** * @category mapping * @since 1.0.0 */ export const map: { (f: (a: A, i: number) => B): (self: ReadonlyArray) => Array (self: ReadonlyArray, f: (a: A, i: number) => B): Array } = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map(f)) /** * @category mapping * @since 1.0.0 */ export const mapNonEmpty: { (f: (a: A, i: number) => B): (self: readonly [A, ...Array]) => [B, ...Array] (self: readonly [A, ...Array], f: (a: A, i: number) => B): [B, ...Array] } = map as any const imap = covariant.imap(map) /** * @category instances * @since 1.0.0 */ export const Covariant: covariant.Covariant = { imap, map } /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { imap } /** * @category mapping * @since 1.0.0 */ export const tupled: (self: ReadonlyArray) => Array<[A]> = invariant .tupled(Invariant) as any /** * @category mapping * @since 1.0.0 */ export const flap: { (a: A, self: ReadonlyArray<(a: A) => B>): Array (self: ReadonlyArray<(a: A) => B>): (a: A) => Array } = covariant.flap(Covariant) as any /** * Maps the success value of this effect to the specified constant value. * * @category mapping * @since 1.0.0 */ export const as: { <_, B>(self: ReadonlyArray<_>, b: B): Array (b: B): <_>(self: ReadonlyArray<_>) => Array } = covariant.as(Covariant) as any /** * @category instances * @since 1.0.0 */ export const Pointed: pointed.Pointed = { of, imap, map } /** * @category sequencing * @since 1.0.0 */ export const flatMap: { (f: (a: A, i: number) => ReadonlyArray): (self: ReadonlyArray) => Array (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array } = dual( 2, (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { if (isEmpty(self)) { return [] } const out: Array = [] for (let i = 0; i < self.length; i++) { out.push(...f(self[i], i)) } return out } ) /** * @category sequencing * @since 1.0.0 */ export const flatMapNonEmpty: { ( f: (a: A, i: number) => NonEmptyReadonlyArray ): (self: NonEmptyReadonlyArray) => NonEmptyArray ( self: NonEmptyReadonlyArray, f: (a: A, i: number) => NonEmptyReadonlyArray ): NonEmptyArray } = flatMap as any /** * @category instances * @since 1.0.0 */ export const FlatMap: flatMap_.FlatMap = { flatMap } /** * @category sequencing * @since 1.0.0 */ export const flatten: (self: ReadonlyArray>) => Array = flatMap_ .flatten(FlatMap) as any /** * @category sequencing * @since 1.0.0 */ export const flattenNonEmpty: ( self: NonEmptyReadonlyArray> ) => NonEmptyArray = flatMapNonEmpty(identity) /** * @since 1.0.0 */ export const composeKleisliArrow: { ( afb: (a: A) => ReadonlyArray, bfc: (b: B) => ReadonlyArray ): (a: A) => ReadonlyArray ( bfc: (b: B) => ReadonlyArray ): (afb: (a: A) => ReadonlyArray) => (a: A) => ReadonlyArray } = flatMap_.composeKleisliArrow(FlatMap) /** * @category instances * @since 1.0.0 */ export const Chainable: chainable.Chainable = { imap, map, flatMap } /** * @category filtering * @since 1.0.0 */ export const filterMap: { (f: (a: A, i: number) => Option): (self: Iterable) => Array (self: Iterable, f: (a: A, i: number) => Option): Array } = dual( 2, (self: Iterable, f: (a: A, i: number) => Option): Array => { const as = fromIterable(self) const out: Array = [] for (let i = 0; i < as.length; i++) { const o = f(as[i], i) if (O.isSome(o)) { out.push(o.value) } } return out } ) /** * @category filtering * @since 1.0.0 */ export const partitionMap: { (f: (a: A, i: number) => Either): (self: Iterable) => [Array, Array] (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] } = dual( 2, (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] => { const left: Array = [] const right: Array = [] const as = fromIterable(self) for (let i = 0; i < as.length; i++) { const e = f(as[i], i) if (E.isLeft(e)) { left.push(e.left) } else { right.push(e.right) } } return [left, right] } ) /** * @category instances * @since 1.0.0 */ export const Filterable: filterable.Filterable = { partitionMap, filterMap } /** * @category filtering * @since 1.0.0 */ export const compact: (self: Iterable>) => Array = filterMap(identity) /** * @category filtering * @since 1.0.0 */ export const filter: { ( refinement: (a: A, i: number) => a is B ): (self: Iterable) => Array (predicate: (a: A, i: number) => boolean): (self: Iterable) => Array ( self: Iterable, refinement: (a: A, i: number) => a is B ): Array (self: Iterable, predicate: (a: A, i: number) => boolean): Array } = dual( 2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { const as = fromIterable(self) const out: Array = [] for (let i = 0; i < as.length; i++) { if (predicate(as[i], i)) { out.push(as[i]) } } return out } ) /** * @category filtering * @since 1.0.0 */ export const partition: { (refinement: (a: A, i: number) => a is B): ( self: Iterable ) => [Array, Array] ( predicate: (a: A, i: number) => boolean ): (self: Iterable) => [Array, Array] ( self: Iterable, refinement: (a: A, i: number) => a is B ): [Array, Array] ( self: Iterable, predicate: (a: A, i: number) => boolean ): [Array, Array] } = dual( 2, ( self: Iterable, predicate: (a: A, i: number) => boolean ): [Array, Array] => { const left: Array = [] const right: Array = [] const as = fromIterable(self) for (let i = 0; i < as.length; i++) { if (predicate(as[i], i)) { right.push(as[i]) } else { left.push(as[i]) } } return [left, right] } ) /** * @category filtering * @since 1.0.0 */ export const separate: (self: Iterable>) => [Array, Array] = partitionMap( identity ) /** * @category traversing * @since 1.0.0 */ export const traverseNonEmpty = ( F: semiApplicative.SemiApplicative ): { ( f: (a: A, i: number) => Kind ): (self: NonEmptyReadonlyArray) => Kind> ( self: NonEmptyReadonlyArray, f: (a: A, i: number) => Kind ): Kind> } => dual(2, ( self: NonEmptyReadonlyArray, f: (a: A, i: number) => Kind ): Kind> => { const [head, ...tail] = mapNonEmpty(self, f) return F.productMany(head, tail) }) /** * @category traversing * @since 1.0.0 */ export const traverse = (F: applicative.Applicative): { ( f: (a: A, i: number) => Kind ): (self: Iterable) => Kind> ( self: Iterable, f: (a: A, i: number) => Kind ): Kind> } => dual(2, ( self: Iterable, f: (a: A, i: number) => Kind ): Kind> => F.productAll(fromIterable(self).map(f))) /** * @category traversing * @since 1.0.0 */ export const sequence = ( F: applicative.Applicative ): ( self: ReadonlyArray> ) => Kind> => traverse(F)(identity) /** * @category instances * @since 1.0.0 */ export const Traversable: traversable.Traversable = { traverse: traverse as any } /** * @category traversing * @since 1.0.0 */ export const traverseTap: ( F: applicative.Applicative ) => { ( self: ReadonlyArray, f: (a: A) => Kind ): Kind> ( f: (a: A) => Kind ): (self: ReadonlyArray) => Kind> } = traversable.traverseTap(Traversable) as any /** * @category traversing * @since 1.0.0 */ export const sequenceNonEmpty = ( F: semiApplicative.SemiApplicative ): (( self: NonEmptyReadonlyArray> ) => Kind>) => traverseNonEmpty(F)(identity) const product = (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> => { if (isEmpty(self) || isEmpty(that)) { return empty() } const out: Array<[A, B]> = [] for (let i = 0; i < self.length; i++) { for (let j = 0; j < that.length; j++) { out.push([self[i], that[j]]) } } return out } const productMany = semiProduct.productMany(map, product) /** * @category instances * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { imap, product, productMany } /** * @category instances * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, product, productMany } /** * @since 1.0.0 */ export const ap: { (self: ReadonlyArray<(a: A) => B>, that: ReadonlyArray): Array (that: ReadonlyArray): (self: ReadonlyArray<(a: A) => B>) => Array } = semiApplicative.ap(SemiApplicative) as any /** * Lifts a binary function into `ReadonlyArray`. * * @param f - The function to lift. * * @category lifting * @since 1.0.0 */ export const lift2: (f: (a: A, b: B) => C) => { (self: ReadonlyArray, that: ReadonlyArray): Array (that: ReadonlyArray): (self: ReadonlyArray) => Array } = semiApplicative.lift2(SemiApplicative) as any /** * @category instances * @since 1.0.0 */ export const Product: product_.Product = { of, imap, product, productMany, productAll: (collection) => { const arrays = fromIterable(collection) return isEmpty(arrays) ? empty() : SemiProduct.productMany(arrays[0], arrays.slice(1)) } } /** * @category instances * @since 1.0.0 */ export const Applicative: applicative.Applicative = { imap, of, map, product, productMany, productAll: Product.productAll } /** * @category lifting * @since 1.0.0 */ export const liftMonoid: (M: Monoid) => Monoid> = applicative .getMonoid( Applicative ) /** * @category instances * @since 1.0.0 */ export const Monad: monad.Monad = { imap, of, map, flatMap } /** * @category folding * @since 1.0.0 */ export const reduce: { (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } = dual( 3, (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => fromIterable(self).reduce((b, a, i) => f(b, a, i), b) ) /** * @category folding * @since 1.0.0 */ export const reduceRight: { (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } = dual( 3, (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => fromIterable(self).reduceRight((b, a, i) => f(b, a, i), b) ) /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { reduce } /** * @category folding * @since 1.0.0 */ export const combineMap = (Monoid: Monoid): { (f: (a: A, i: number) => M): (self: Iterable) => M (self: Iterable, f: (a: A, i: number) => M): M } => dual( 2, (self: Iterable, f: (a: A, i: number) => M): M => fromIterable(self).reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) ) /** * @category folding * @since 1.0.0 */ export const combineMapNonEmpty = (S: Semigroup): { (f: (a: A, i: number) => S): (self: NonEmptyReadonlyArray) => S (self: NonEmptyReadonlyArray, f: (a: A, i: number) => S): S } => dual( 2, (self: NonEmptyReadonlyArray, f: (a: A, i: number) => S): S => tailNonEmpty(self).reduce((s, a, i) => S.combine(s, f(a, i + 1)), f(headNonEmpty(self), 0)) ) /** * @category folding * @since 1.0.0 */ export const reduceKind: ( G: monad.Monad ) => { ( b: B, f: (b: B, a: A) => Kind ): (self: ReadonlyArray) => Kind ( self: ReadonlyArray, b: B, f: (b: B, a: A) => Kind ): Kind } = foldable.reduceKind(Foldable) /** * @category folding * @since 1.0.0 */ export const coproductMapKind: ( G: Coproduct ) => { ( f: (a: A) => Kind ): (self: ReadonlyArray) => Kind ( self: ReadonlyArray, f: (a: A) => Kind ): Kind } = foldable.coproductMapKind(Foldable) /** * @category filtering * @since 1.0.0 */ export const traversePartitionMap = ( F: applicative.Applicative ): { ( f: (a: A) => Kind> ): (self: ReadonlyArray) => Kind, Array]> ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind, Array]> } => dual(2, ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind, Array]> => { return F.map(traverse(F)(self, f), separate) }) /** * @category filtering * @since 1.0.0 */ export const traverseFilterMap = ( F: applicative.Applicative ): { ( f: (a: A) => Kind> ): (self: ReadonlyArray) => Kind> ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind> } => dual(2, ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind> => { return F.map(traverse(F)(self, f), compact) }) /** * @category instances * @since 1.0.0 */ export const TraversableFilterable: traversableFilterable.TraversableFilterable< ReadonlyArrayTypeLambda > = { traversePartitionMap: traversePartitionMap as any, traverseFilterMap: traverseFilterMap as any } /** * Filter values inside a context. * * @since 1.0.0 */ export const traverseFilter: ( F: applicative.Applicative ) => { ( predicate: (a: A) => Kind ): (self: ReadonlyArray) => Kind> ( self: ReadonlyArray, predicate: (a: A) => Kind ): Kind> } = traversableFilterable.traverseFilter(TraversableFilterable) as any /** * @since 1.0.0 */ export const traversePartition: ( F: applicative.Applicative ) => { ( predicate: (a: A) => Kind ): (self: ReadonlyArray) => Kind, Array]> ( self: ReadonlyArray, predicate: (a: A) => Kind ): Kind, Array]> } = traversableFilterable.traversePartition(TraversableFilterable) as any /** * @category lifting * @since 1.0.0 */ export const liftPredicate: { (refinement: Refinement): (c: C) => Array (predicate: Predicate): (b: B) => Array } = (predicate: Predicate) => (b: B) => predicate(b) ? [b] : [] /** * @category lifting * @since 1.0.0 */ export const liftOption = , B>( f: (...a: A) => Option ) => (...a: A): Array => fromOption(f(...a)) /** * @category conversions * @since 1.0.0 */ export const fromNullable = (a: A): Array> => a == null ? empty() : [a as NonNullable] /** * @category lifting * @since 1.0.0 */ export const liftNullable = , B>( f: (...a: A) => B | null | undefined ): (...a: A) => Array> => (...a) => fromNullable(f(...a)) /** * @category sequencing * @since 1.0.0 */ export const flatMapNullable: { (f: (a: A) => B | null | undefined): (self: ReadonlyArray) => Array> (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> } = dual( 2, (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> => isNonEmpty(self) ? fromNullable(f(headNonEmpty(self))) : empty() ) /** * @category lifting * @since 1.0.0 */ export const liftEither = , E, B>( f: (...a: A) => Either ) => (...a: A): Array => { const e = f(...a) return E.isLeft(e) ? [] : [e.right] } /** * Check if a predicate holds true for every `ReadonlyArray` member. * * @category lifting * @since 1.0.0 */ export function every( refinement: Refinement ): Refinement, ReadonlyArray> export function every(predicate: Predicate): Predicate> export function every(predicate: Predicate): Predicate> { return (self) => self.every(predicate) } /** * Check if a predicate holds true for any `ReadonlyArray` member. * * @category predicates * @since 1.0.0 */ export const some = (predicate: Predicate) => (self: ReadonlyArray): self is NonEmptyReadonlyArray => self.some(predicate) /** * Fold an `Iterable`, accumulating values in some `Monoid`, combining adjacent elements * using the specified separator. * * @since 1.0.0 */ export const intercalate = (M: Monoid): { (middle: A): (self: Iterable) => A (self: Iterable, middle: A): A } => dual( 2, (self: Iterable, middle: A): A => { const as = fromIterable(self) return isNonEmpty(as) ? intercalateNonEmpty(M)(as, middle) : M.empty } ) /** * Places an element in between members of a `NonEmptyReadonlyArray`, then folds the results using the provided `Semigroup`. * * @since 1.0.0 */ export const intercalateNonEmpty = ( S: Semigroup ): { (middle: A): (self: NonEmptyReadonlyArray) => A (self: NonEmptyReadonlyArray, middle: A): A } => dual( 2, (self: NonEmptyReadonlyArray, middle: A): A => semigroup.intercalate(S, middle).combineMany(headNonEmpty(self), tailNonEmpty(self)) ) /** * @since 1.0.0 */ export const join: { (middle: string): (self: ReadonlyArray) => string (self: ReadonlyArray, middle: string): string } = intercalate(string.Monoid) /** * @since 1.0.0 */ export const extend: { (f: (as: ReadonlyArray) => B): (self: ReadonlyArray) => Array (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array } = dual( 2, (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array => self.map((_, i, as) => f(as.slice(i))) ) /** * @since 1.0.0 */ export const min = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { const S = semigroup.min(O) return (self) => self.reduce(S.combine) } /** * @since 1.0.0 */ export const max = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { const S = semigroup.max(O) return (self) => self.reduce(S.combine) } /** * @category constructors * @since 1.0.0 */ export const unfold = (b: B, f: (b: B) => Option): Array => { const out: Array = [] let next: B = b let o: Option while (O.isSome(o = f(next))) { const [a, b] = o.value out.push(a) next = b } return out } /** * @category instances * @since 1.0.0 */ export const getUnionSemigroup = ( isEquivalent: (self: A, that: A) => boolean ): Semigroup> => semigroup.make(union(isEquivalent)) as any /** * @category instances * @since 1.0.0 */ export const getUnionMonoid = ( isEquivalent: (self: A, that: A) => boolean ): Monoid> => { const S = getUnionSemigroup(isEquivalent) return ({ combine: S.combine, combineMany: S.combineMany, combineAll: (collection) => S.combineMany([], collection), empty: [] }) } /** * @category instances * @since 1.0.0 */ export const getIntersectionSemigroup = ( isEquivalent: (self: A, that: A) => boolean ): Semigroup> => semigroup.make(intersection(isEquivalent)) as any /** * Returns a `Semigroup` for `ReadonlyArray`. * * @category instances * @since 1.0.0 */ export const getSemigroup: () => Semigroup> = semigroup.array /** * Returns a `Monoid` for `ReadonlyArray`. * * @category instances * @since 1.0.0 */ export const getMonoid: () => Monoid> = monoid.array /** * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. * If all elements are equal, the arrays are then compared based on their length. * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. * * @category lifting * @since 1.0.0 */ export const getOrder: (O: Order) => Order> = order.array // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- /** * @category do notation * @since 1.0.0 */ export const bindTo: { (name: N): (self: ReadonlyArray) => Array<{ [K in N]: A }> (self: ReadonlyArray, name: N): Array<{ [K in N]: A }> } = invariant.bindTo(Invariant) as any const let_: { ( name: Exclude, f: (a: A) => B ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: ReadonlyArray, name: Exclude, f: (a: A) => B ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = covariant.let(Covariant) as any export { /** * @category do notation * @since 1.0.0 */ let_ as let } /** * @category do notation * @since 1.0.0 */ export const Do: ReadonlyArray<{}> = of_.Do(Of) /** * @category do notation * @since 1.0.0 */ export const bind: { ( name: Exclude, f: (a: A) => ReadonlyArray ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: ReadonlyArray, name: Exclude, f: (a: A) => ReadonlyArray ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = chainable.bind(Chainable) as any /** * A variant of `bind` that sequentially ignores the scope. * * @category do notation * @since 1.0.0 */ export const andThenBind: { ( name: Exclude, that: ReadonlyArray ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: ReadonlyArray, name: Exclude, that: ReadonlyArray ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = semiProduct.andThenBind(SemiProduct) as any