/** * This module provides utility functions for working with tuples in TypeScript. * * @since 1.0.0 */ import * as Equivalence from "@effect/data/Equivalence" import { dual } from "@effect/data/Function" import type { TypeLambda } from "@effect/data/HKT" import * as order from "@effect/data/Order" /** * @category type lambdas * @since 1.0.0 */ export interface TupleTypeLambda extends TypeLambda { readonly type: [this["Out1"], this["Target"]] } /** * Constructs a new tuple from the provided values. * * @param elements - The list of elements to create the tuple from. * * @example * import { tuple } from "@effect/data/Tuple" * * assert.deepStrictEqual(tuple(1, 'hello', true), [1, 'hello', true]) * * @category constructors * @since 1.0.0 */ export const tuple = >(...elements: A): A => elements /** * Return the first element of a tuple. * * @param self - A tuple of length `2`. * * @example * import { getFirst } from "@effect/data/Tuple" * * assert.deepStrictEqual(getFirst(["hello", 42]), "hello") * * @category getters * @since 1.0.0 */ export const getFirst = (self: readonly [L, R]): L => self[0] /** * Return the second element of a tuple. * * @param self - A tuple of length `2`. * * @example * import { getSecond } from "@effect/data/Tuple" * * assert.deepStrictEqual(getSecond(["hello", 42]), 42) * * @category getters * @since 1.0.0 */ export const getSecond = (self: readonly [L, R]): R => self[1] /** * Transforms both elements of a tuple using the given functions. * * @param self - A tuple of length `2`. * @param f - The function to transform the first element of the tuple. * @param g - The function to transform the second element of the tuple. * * @example * import { mapBoth } from "@effect/data/Tuple" * * assert.deepStrictEqual( * mapBoth(["hello", 42], { onFirst: s => s.toUpperCase(), onSecond: n => n.toString() }), * ["HELLO", "42"] * ) * * @category mapping * @since 1.0.0 */ export const mapBoth: { (options: { readonly onFirst: (e: L1) => L2 readonly onSecond: (a: R1) => R2 }): (self: readonly [L1, R1]) => [L2, R2] (self: readonly [L1, R1], options: { readonly onFirst: (e: L1) => L2 readonly onSecond: (a: R1) => R2 }): [L2, R2] } = dual( 2, ( self: readonly [L1, R1], { onFirst, onSecond }: { readonly onFirst: (e: L1) => L2 readonly onSecond: (a: R1) => R2 } ): [L2, R2] => [onFirst(self[0]), onSecond(self[1])] ) /** * Transforms the first component of a tuple using a given function. * * @param self - A tuple of length `2`. * @param f - The function to transform the first element of the tuple. * * @example * import { mapFirst } from "@effect/data/Tuple" * * assert.deepStrictEqual( * mapFirst(["hello", 42], s => s.toUpperCase()), * ["HELLO", 42] * ) * * @category mapping * @since 1.0.0 */ export const mapFirst: { (f: (left: L1) => L2): (self: readonly [L1, R]) => [L2, R] (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] } = dual(2, (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] => [f(self[0]), self[1]]) /** * Transforms the second component of a tuple using a given function. * * @param self - A tuple of length `2`. * @param f - The function to transform the second element of the tuple. * * @example * import { mapSecond } from "@effect/data/Tuple" * * assert.deepStrictEqual( * mapSecond(["hello", 42], n => n.toString()), * ["hello", "42"] * ) * * @category mapping * @since 1.0.0 */ export const mapSecond: { (f: (right: R1) => R2): (self: readonly [L, R1]) => [L, R2] (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] } = dual(2, (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] => [self[0], f(self[1])]) /** * Swaps the two elements of a tuple. * * @param self - A tuple of length `2`. * * @example * import { swap } from "@effect/data/Tuple" * * assert.deepStrictEqual(swap(["hello", 42]), [42, "hello"]) * * @since 1.0.0 */ export const swap = (self: readonly [L, R]): [R, L] => [self[1], self[0]] /** * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple * by applying each `Equivalence` to the corresponding element of the tuple. * * @category combinators * @since 1.0.0 */ export const getEquivalence: >>( ...isEquivalents: T ) => Equivalence.Equivalence< Readonly<{ [I in keyof T]: [T[I]] extends [Equivalence.Equivalence] ? A : never }> > = Equivalence.tuple /** * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element * of the tuple. * * @category combinators * @since 1.0.0 */ export const getOrder: >>( ...elements: T ) => order.Order<{ [I in keyof T]: [T[I]] extends [order.Order] ? A : never }> = order.tuple /** * Appends an element to the end of a tuple. * * @category concatenating * @since 1.0.0 */ export const appendElement: { (that: B): >(self: A) => [...A, B] , B>(self: A, that: B): [...A, B] } = dual(2, , B>(self: A, that: B): [...A, B] => [...self, that]) /* TODO: - at - swap */