Skip to main content
Glama
ssv445

Lorem Ipsum MCP Server

by ssv445
List.ts39.6 kB
/** * A data type for immutable linked lists representing ordered collections of elements of type `A`. * * This data type is optimal for last-in-first-out (LIFO), stack-like access patterns. If you need another access pattern, for example, random access or FIFO, consider using a collection more suited to this than `List`. * * **Performance** * * - Time: `List` has `O(1)` prepend and head/tail access. Most other operations are `O(n)` on the number of elements in the list. This includes the index-based lookup of elements, `length`, `append` and `reverse`. * - Space: `List` implements structural sharing of the tail list. This means that many operations are either zero- or constant-memory cost. * * @since 2.0.0 */ /** * This file is ported from * * Scala (https://www.scala-lang.org) * * Copyright EPFL and Lightbend, Inc. * * Licensed under Apache License 2.0 * (http://www.apache.org/licenses/LICENSE-2.0). */ import * as Arr from "./Array.js" import * as Chunk from "./Chunk.js" import * as Either from "./Either.js" import * as Equal from "./Equal.js" import * as Equivalence from "./Equivalence.js" import { dual, identity, unsafeCoerce } from "./Function.js" import * as Hash from "./Hash.js" import { format, type Inspectable, NodeInspectSymbol, toJSON } from "./Inspectable.js" import type { nonEmpty, NonEmptyIterable } from "./NonEmptyIterable.js" import * as Option from "./Option.js" import type { Pipeable } from "./Pipeable.js" import { pipeArguments } from "./Pipeable.js" import { hasProperty, type Predicate, type Refinement } from "./Predicate.js" import type { NoInfer } from "./Types.js" /** * Represents an immutable linked list of elements of type `A`. * * A `List` is optimal for last-in-first-out (LIFO), stack-like access patterns. * If you need another access pattern, for example, random access or FIFO, * consider using a collection more suited for that other than `List`. * * @since 2.0.0 * @category models */ export type List<A> = Cons<A> | Nil<A> /** * @since 2.0.0 * @category symbol */ export const TypeId: unique symbol = Symbol.for("effect/List") /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof TypeId /** * @since 2.0.0 * @category models */ export interface Nil<out A> extends Iterable<A>, Equal.Equal, Pipeable, Inspectable { readonly [TypeId]: TypeId readonly _tag: "Nil" } /** * @since 2.0.0 * @category models */ export interface Cons<out A> extends NonEmptyIterable<A>, Equal.Equal, Pipeable, Inspectable { readonly [TypeId]: TypeId readonly _tag: "Cons" readonly head: A readonly tail: List<A> } /** * Converts the specified `List` to an `Array`. * * @category conversions * @since 2.0.0 */ export const toArray = <A>(self: List<A>): Array<A> => Arr.fromIterable(self) /** * @category equivalence * @since 2.0.0 */ export const getEquivalence = <A>(isEquivalent: Equivalence.Equivalence<A>): Equivalence.Equivalence<List<A>> => Equivalence.mapInput(Arr.getEquivalence(isEquivalent), toArray<A>) const _equivalence = getEquivalence(Equal.equals) const ConsProto: Omit<Cons<unknown>, "head" | "tail" | typeof nonEmpty> = { [TypeId]: TypeId, _tag: "Cons", toString(this: Cons<unknown>) { return format(this.toJSON()) }, toJSON(this: Cons<unknown>) { return { _id: "List", _tag: "Cons", values: toArray(this).map(toJSON) } }, [NodeInspectSymbol]() { return this.toJSON() }, [Equal.symbol](this: Cons<unknown>, that: unknown): boolean { return isList(that) && this._tag === that._tag && _equivalence(this, that) }, [Hash.symbol](this: Cons<unknown>): number { return Hash.cached(this, Hash.array(toArray(this))) }, [Symbol.iterator](this: Cons<unknown>): Iterator<unknown> { let done = false // eslint-disable-next-line @typescript-eslint/no-this-alias let self: List<unknown> = this return { next() { if (done) { return this.return!() } if (self._tag === "Nil") { done = true return this.return!() } const value: unknown = self.head self = self.tail return { done, value } }, return(value?: unknown) { if (!done) { done = true } return { done: true, value } } } }, pipe() { return pipeArguments(this, arguments) } } interface MutableCons<A> extends Cons<A> { head: A tail: List<A> } const makeCons = <A>(head: A, tail: List<A>): MutableCons<A> => { const cons = Object.create(ConsProto) cons.head = head cons.tail = tail return cons } const NilHash = Hash.string("Nil") const NilProto: Nil<unknown> = { [TypeId]: TypeId, _tag: "Nil", toString() { return format(this.toJSON()) }, toJSON() { return { _id: "List", _tag: "Nil" } }, [NodeInspectSymbol]() { return this.toJSON() }, [Hash.symbol](): number { return NilHash }, [Equal.symbol](that: unknown): boolean { return isList(that) && this._tag === that._tag }, [Symbol.iterator](): Iterator<unknown> { return { next() { return { done: true, value: undefined } } } }, pipe() { return pipeArguments(this, arguments) } } as const const _Nil = Object.create(NilProto) as Nil<never> /** * Returns `true` if the specified value is a `List`, `false` otherwise. * * @since 2.0.0 * @category refinements */ export const isList: { /** * Returns `true` if the specified value is a `List`, `false` otherwise. * * @since 2.0.0 * @category refinements */ <A>(u: Iterable<A>): u is List<A> /** * Returns `true` if the specified value is a `List`, `false` otherwise. * * @since 2.0.0 * @category refinements */ (u: unknown): u is List<unknown> } = (u: unknown): u is List<unknown> => hasProperty(u, TypeId) /** * Returns `true` if the specified value is a `List.Nil<A>`, `false` otherwise. * * @since 2.0.0 * @category refinements */ export const isNil = <A>(self: List<A>): self is Nil<A> => self._tag === "Nil" /** * Returns `true` if the specified value is a `List.Cons<A>`, `false` otherwise. * * @since 2.0.0 * @category refinements */ export const isCons = <A>(self: List<A>): self is Cons<A> => self._tag === "Cons" /** * Returns the number of elements contained in the specified `List` * * @since 2.0.0 * @category getters */ export const size = <A>(self: List<A>): number => { let these = self let len = 0 while (!isNil(these)) { len += 1 these = these.tail } return len } /** * Constructs a new empty `List<A>`. * * @since 2.0.0 * @category constructors */ export const nil = <A = never>(): List<A> => _Nil /** * Constructs a new `List.Cons<A>` from the specified `head` and `tail` values. * * @since 2.0.0 * @category constructors */ export const cons = <A>(head: A, tail: List<A>): Cons<A> => makeCons(head, tail) /** * Constructs a new empty `List<A>`. * * Alias of {@link nil}. * * @since 2.0.0 * @category constructors */ export const empty = nil /** * Constructs a new `List<A>` from the specified value. * * @since 2.0.0 * @category constructors */ export const of = <A>(value: A): Cons<A> => makeCons(value, _Nil) /** * Creates a new `List` from an iterable collection of values. * * @since 2.0.0 * @category constructors */ export const fromIterable = <A>(prefix: Iterable<A>): List<A> => { const iterator = prefix[Symbol.iterator]() let next: IteratorResult<A> if ((next = iterator.next()) && !next.done) { const result = makeCons(next.value, _Nil) let curr = result while ((next = iterator.next()) && !next.done) { const temp = makeCons(next.value, _Nil) curr.tail = temp curr = temp } return result } else { return _Nil } } /** * Constructs a new `List<A>` from the specified values. * * @since 2.0.0 * @category constructors */ export const make = <Elements extends readonly [any, ...Array<any>]>( ...elements: Elements ): Cons<Elements[number]> => fromIterable(elements) as any /** * Appends the specified element to the end of the `List`, creating a new `Cons`. * * @category concatenating * @since 2.0.0 */ export const append: { /** * Appends the specified element to the end of the `List`, creating a new `Cons`. * * @category concatenating * @since 2.0.0 */ <B>(element: B): <A>(self: List<A>) => Cons<A | B> /** * Appends the specified element to the end of the `List`, creating a new `Cons`. * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, element: B): Cons<A | B> } = dual(2, <A, B>(self: List<A>, element: B): Cons<A | B> => appendAll(self, of(element))) /** * Concatenates two lists, combining their elements. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.appendAll(List.make("a", "b")), List.toArray), * [1, 2, "a", "b"] * ) * ``` * * @category concatenating * @since 2.0.0 */ export const appendAll: { /** * Concatenates two lists, combining their elements. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.appendAll(List.make("a", "b")), List.toArray), * [1, 2, "a", "b"] * ) * ``` * * @category concatenating * @since 2.0.0 */ <S extends List<any>, T extends List<any>>(that: T): (self: S) => List.OrNonEmpty<S, T, List.Infer<S> | List.Infer<T>> /** * Concatenates two lists, combining their elements. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.appendAll(List.make("a", "b")), List.toArray), * [1, 2, "a", "b"] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, that: Cons<B>): Cons<A | B> /** * Concatenates two lists, combining their elements. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.appendAll(List.make("a", "b")), List.toArray), * [1, 2, "a", "b"] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Cons<A>, that: List<B>): Cons<A | B> /** * Concatenates two lists, combining their elements. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.appendAll(List.make("a", "b")), List.toArray), * [1, 2, "a", "b"] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, that: List<B>): List<A | B> } = dual(2, <A, B>(self: List<A>, that: List<B>): List<A | B> => prependAll(that, self)) /** * Prepends the specified element to the beginning of the list. * * @category concatenating * @since 2.0.0 */ export const prepend: { /** * Prepends the specified element to the beginning of the list. * * @category concatenating * @since 2.0.0 */ <B>(element: B): <A>(self: List<A>) => Cons<A | B> /** * Prepends the specified element to the beginning of the list. * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, element: B): Cons<A | B> } = dual(2, <A, B>(self: List<A>, element: B): Cons<A | B> => cons</** * Prepends the specified element to the beginning of the list. * * @category concatenating * @since 2.0.0 */ A | B>(element, self)) /** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ export const prependAll: { /** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ <S extends List<any>, T extends List<any>>(that: T): (self: S) => List.OrNonEmpty<S, T, List.Infer<S> | List.Infer<T>> /** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, that: Cons<B>): Cons<A | B> /** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: Cons<A>, that: List<B>): Cons<A | B> /** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, that: List<B>): List<A | B> } = dual(2, <A, B>(self: List<A>, prefix: List<B>): List<A | B> => { if (isNil(self)) { return prefix } else if (isNil(prefix)) { return self } else { const result = makeCons</** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ A | B>(prefix.head, self) let curr = result let that = prefix.tail while (!isNil(that)) { const temp = makeCons</** * Prepends the specified prefix list to the beginning of the specified list. * If either list is non-empty, the result is also a non-empty list. * * @example * ```ts * import * as assert from "node:assert" * import { List } from "effect" * * assert.deepStrictEqual( * List.make(1, 2).pipe(List.prependAll(List.make("a", "b")), List.toArray), * ["a", "b", 1, 2] * ) * ``` * * @category concatenating * @since 2.0.0 */ A | B>(that.head, self) curr.tail = temp curr = temp that = that.tail } return result } }) /** * Prepends the specified prefix list (in reverse order) to the beginning of the * specified list. * * @category concatenating * @since 2.0.0 */ export const prependAllReversed: { /** * Prepends the specified prefix list (in reverse order) to the beginning of the * specified list. * * @category concatenating * @since 2.0.0 */ <B>(prefix: List<B>): <A>(self: List<A>) => List<A | B> /** * Prepends the specified prefix list (in reverse order) to the beginning of the * specified list. * * @category concatenating * @since 2.0.0 */ <A, B>(self: List<A>, prefix: List<B>): List<A | B> } = dual(2, <A, B>(self: List<A>, prefix: List<B>): List<A | B> => { let out: List<A | B> = self let pres = prefix while (isCons(pres)) { out = makeCons(pres.head, out) pres = pres.tail } return out }) /** * Drops the first `n` elements from the specified list. * * @since 2.0.0 * @category combinators */ export const drop: { /** * Drops the first `n` elements from the specified list. * * @since 2.0.0 * @category combinators */ (n: number): <A>(self: List<A>) => List<A> /** * Drops the first `n` elements from the specified list. * * @since 2.0.0 * @category combinators */ <A>(self: List<A>, n: number): List<A> } = dual(2, <A>(self: List<A>, n: number): List<A> => { if (n <= 0) { return self } if (n >= size(self)) { return _Nil } let these = self let i = 0 while (!isNil(these) && i < n) { these = these.tail i += 1 } return these }) /** * Check if a predicate holds true for every `List` element. * * @since 2.0.0 * @category elements */ export const every: { /** * Check if a predicate holds true for every `List` element. * * @since 2.0.0 * @category elements */ <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: List<A>) => self is List<B> /** * Check if a predicate holds true for every `List` element. * * @since 2.0.0 * @category elements */ <A>(predicate: Predicate<A>): (self: List<A>) => boolean /** * Check if a predicate holds true for every `List` element. * * @since 2.0.0 * @category elements */ <A, B extends A>(self: List<A>, refinement: Refinement<A, B>): self is List<B> /** * Check if a predicate holds true for every `List` element. * * @since 2.0.0 * @category elements */ <A>(self: List<A>, predicate: Predicate<A>): boolean } = dual(2, <A, B extends A>(self: List<A>, refinement: Refinement<A, B>): self is List<B> => { for (const a of self) { if (!refinement(a)) { return false } } return true }) /** * Check if a predicate holds true for some `List` element. * * @since 2.0.0 * @category elements */ export const some: { /** * Check if a predicate holds true for some `List` element. * * @since 2.0.0 * @category elements */ <A>(predicate: Predicate<NoInfer<A>>): (self: List<A>) => self is Cons<A> /** * Check if a predicate holds true for some `List` element. * * @since 2.0.0 * @category elements */ <A>(self: List<A>, predicate: Predicate<A>): self is Cons<A> } = dual(2, <A>(self: List<A>, predicate: Predicate<A>): self is Cons<A> => { let these = self while (!isNil(these)) { if (predicate(these.head)) { return true } these = these.tail } return false }) /** * Filters a list using the specified predicate. * * @since 2.0.0 * @category combinators */ export const filter: { /** * Filters a list using the specified predicate. * * @since 2.0.0 * @category combinators */ <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: List<A>) => List<B> /** * Filters a list using the specified predicate. * * @since 2.0.0 * @category combinators */ <A>(predicate: Predicate<NoInfer<A>>): (self: List<A>) => List<A> /** * Filters a list using the specified predicate. * * @since 2.0.0 * @category combinators */ <A, B extends A>(self: List<A>, refinement: Refinement<A, B>): List<B> /** * Filters a list using the specified predicate. * * @since 2.0.0 * @category combinators */ <A>(self: List<A>, predicate: Predicate<A>): List<A> } = dual(2, <A>(self: List<A>, predicate: Predicate<A>): List<A> => noneIn(self, predicate, false)) // everything seen so far is not included const noneIn = <A>( self: List<A>, predicate: Predicate<A>, isFlipped: boolean ): List<A> => { while (true) { if (isNil(self)) { return _Nil } else { if (predicate(self.head) !== isFlipped) { return allIn(self, self.tail, predicate, isFlipped) } else { self = self.tail } } } } // everything from 'start' is included, if everything from this point is in we can return the origin // start otherwise if we discover an element that is out we must create a new partial list. const allIn = <A>( start: List<A>, remaining: List<A>, predicate: Predicate<A>, isFlipped: boolean ): List<A> => { while (true) { if (isNil(remaining)) { return start } else { if (predicate(remaining.head) !== isFlipped) { remaining = remaining.tail } else { return partialFill(start, remaining, predicate, isFlipped) } } } } // we have seen elements that should be included then one that should be excluded, start building const partialFill = <A>( origStart: List<A>, firstMiss: List<A>, predicate: Predicate<A>, isFlipped: boolean ): List<A> => { const newHead = makeCons<A>(unsafeHead(origStart)!, _Nil) let toProcess = unsafeTail(origStart)! as Cons<A> let currentLast = newHead // we know that all elements are :: until at least firstMiss.tail while (!(toProcess === firstMiss)) { const newElem = makeCons(unsafeHead(toProcess)!, _Nil) currentLast.tail = newElem currentLast = unsafeCoerce(newElem) toProcess = unsafeCoerce(toProcess.tail) } // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss. // currentLast is the last element in that list. // now we are going to try and share as much of the tail as we can, only moving elements across when we have to. let next = firstMiss.tail let nextToCopy: Cons<A> = unsafeCoerce(next) // the next element we would need to copy to our list if we cant share. while (!isNil(next)) { // generally recommended is next.isNonEmpty but this incurs an extra method call. const head = unsafeHead(next)! if (predicate(head) !== isFlipped) { next = next.tail } else { // its not a match - do we have outstanding elements? while (!(nextToCopy === next)) { const newElem = makeCons(unsafeHead(nextToCopy)!, _Nil) currentLast.tail = newElem currentLast = newElem nextToCopy = unsafeCoerce(nextToCopy.tail) } nextToCopy = unsafeCoerce(next.tail) next = next.tail } } // we have remaining elements - they are unchanged attach them to the end if (!isNil(nextToCopy)) { currentLast.tail = nextToCopy } return newHead } /** * Filters and maps a list using the specified partial function. The resulting * list may be smaller than the input list due to the possibility of the partial * function not being defined for some elements. * * @since 2.0.0 * @category combinators */ export const filterMap: { /** * Filters and maps a list using the specified partial function. The resulting * list may be smaller than the input list due to the possibility of the partial * function not being defined for some elements. * * @since 2.0.0 * @category combinators */ <A, B>(f: (a: A) => Option.Option<B>): (self: List<A>) => List<B> /** * Filters and maps a list using the specified partial function. The resulting * list may be smaller than the input list due to the possibility of the partial * function not being defined for some elements. * * @since 2.0.0 * @category combinators */ <A, B>(self: List<A>, f: (a: A) => Option.Option<B>): List<B> } = dual(2, <A, B>(self: List<A>, f: (a: A) => Option.Option<B>): List<B> => { const bs: Array<B> = [] for (const a of self) { const oa = f(a) if (Option.isSome(oa)) { bs.push(oa.value) } } return fromIterable(bs) }) /** * Removes all `None` values from the specified list. * * @since 2.0.0 * @category combinators */ export const compact = <A>(self: List<Option.Option<A>>): List<A> => filterMap(self, identity) /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * @category elements * @since 2.0.0 */ export const findFirst: { /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * @category elements * @since 2.0.0 */ <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: List<A>) => Option.Option<B> /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * @category elements * @since 2.0.0 */ <A>(predicate: Predicate<NoInfer<A>>): (self: List<A>) => Option.Option<A> /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * @category elements * @since 2.0.0 */ <A, B extends A>(self: List<A>, refinement: Refinement<A, B>): Option.Option<B> /** * Returns the first element that satisfies the specified * predicate, or `None` if no such element exists. * * @category elements * @since 2.0.0 */ <A>(self: List<A>, predicate: Predicate<A>): Option.Option<A> } = dual(2, <A>(self: List<A>, predicate: Predicate<A>): Option.Option<A> => { let these = self while (!isNil(these)) { if (predicate(these.head)) { return Option.some(these.head) } these = these.tail } return Option.none() }) /** * Applies a function to each element in a list and returns a new list containing the concatenated mapped elements. * * @since 2.0.0 * @category sequencing */ export const flatMap: { /** * Applies a function to each element in a list and returns a new list containing the concatenated mapped elements. * * @since 2.0.0 * @category sequencing */ <S extends List<any>, T extends List<any>>(f: (a: List.Infer<S>, i: number) => T): (self: S) => List.AndNonEmpty<S, T, List.Infer<T>> /** * Applies a function to each element in a list and returns a new list containing the concatenated mapped elements. * * @since 2.0.0 * @category sequencing */ <A, B>(self: Cons<A>, f: (a: A, i: number) => Cons<B>): Cons<B> /** * Applies a function to each element in a list and returns a new list containing the concatenated mapped elements. * * @since 2.0.0 * @category sequencing */ <A, B>(self: List<A>, f: (a: A, i: number) => List<B>): List<B> } = dual(2, <A, B>(self: List<A>, f: (a: A) => List<B>): List<B> => { let rest = self let head: MutableCons<B> | undefined = undefined let tail: MutableCons<B> | undefined = undefined while (!isNil(rest)) { let bs = f(rest.head) while (!isNil(bs)) { const next = makeCons(bs.head, _Nil) if (tail === undefined) { head = next } else { tail.tail = next } tail = next bs = bs.tail } rest = rest.tail } if (head === undefined) { return _Nil } return head }) /** * Applies the specified function to each element of the `List`. * * @since 2.0.0 * @category combinators */ export const forEach: { /** * Applies the specified function to each element of the `List`. * * @since 2.0.0 * @category combinators */ <A, B>(f: (a: A) => B): (self: List<A>) => void /** * Applies the specified function to each element of the `List`. * * @since 2.0.0 * @category combinators */ <A, B>(self: List<A>, f: (a: A) => B): void } = dual(2, <A, B>(self: List<A>, f: (a: A) => B): void => { let these = self while (!isNil(these)) { f(these.head) these = these.tail } }) /** * Returns the first element of the specified list, or `None` if the list is * empty. * * @since 2.0.0 * @category getters */ export const head = <A>(self: List<A>): Option.Option<A> => isNil(self) ? Option.none() : Option.some(self.head) /** * Returns the last element of the specified list, or `None` if the list is * empty. * * @since 2.0.0 * @category getters */ export const last = <A>(self: List<A>): Option.Option<A> => isNil(self) ? Option.none() : Option.some(unsafeLast(self)!) /** * @since 2.0.0 */ export declare namespace List { /** * @since 2.0.0 */ export type Infer<S extends List<any>> = S extends List<infer A> ? A : never /** * @since 2.0.0 */ export type With<S extends List<any>, A> = S extends Cons<any> ? Cons<A> : List<A> /** * @since 2.0.0 */ export type OrNonEmpty<S extends List<any>, T extends List<any>, A> = S extends Cons<any> ? Cons<A> : T extends Cons<any> ? Cons<A> : List<A> /** * @since 2.0.0 */ export type AndNonEmpty<S extends List<any>, T extends List<any>, A> = S extends Cons<any> ? T extends Cons<any> ? Cons<A> : List<A> : List<A> } /** * Applies the specified mapping function to each element of the list. * * @since 2.0.0 * @category mapping */ export const map: { /** * Applies the specified mapping function to each element of the list. * * @since 2.0.0 * @category mapping */ <S extends List<any>, B>(f: (a: List.Infer<S>, i: number) => B): (self: S) => List.With<S, B> /** * Applies the specified mapping function to each element of the list. * * @since 2.0.0 * @category mapping */ <S extends List<any>, B>(self: S, f: (a: List.Infer<S>, i: number) => B): List.With<S, B> } = dual(2, <A, B>(self: List<A>, f: (a: A, i: number) => B): List<B> => { if (isNil(self)) { return self as unknown as List<B> } else { let i = 0 const head = makeCons(f(self.head, i++), _Nil) let nextHead = head let rest = self.tail while (!isNil(rest)) { const next = makeCons(f(rest.head, i++), _Nil) nextHead.tail = next nextHead = next rest = rest.tail } return head } }) /** * Partition a list into two lists, where the first list contains all elements * that did not satisfy the specified predicate, and the second list contains * all elements that did satisfy the specified predicate. * * @since 2.0.0 * @category combinators */ export const partition: { /** * Partition a list into two lists, where the first list contains all elements * that did not satisfy the specified predicate, and the second list contains * all elements that did satisfy the specified predicate. * * @since 2.0.0 * @category combinators */ <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: List<A>) => [excluded: List<Exclude<A, B>>, satisfying: List<B>] /** * Partition a list into two lists, where the first list contains all elements * that did not satisfy the specified predicate, and the second list contains * all elements that did satisfy the specified predicate. * * @since 2.0.0 * @category combinators */ <A>(predicate: Predicate<NoInfer<A>>): (self: List<A>) => [excluded: List<A>, satisfying: List<A>] /** * Partition a list into two lists, where the first list contains all elements * that did not satisfy the specified predicate, and the second list contains * all elements that did satisfy the specified predicate. * * @since 2.0.0 * @category combinators */ <A, B extends A>(self: List<A>, refinement: Refinement<A, B>): [excluded: List<Exclude<A, B>>, satisfying: List<B>] /** * Partition a list into two lists, where the first list contains all elements * that did not satisfy the specified predicate, and the second list contains * all elements that did satisfy the specified predicate. * * @since 2.0.0 * @category combinators */ <A>(self: List<A>, predicate: Predicate<A>): [excluded: List<A>, satisfying: List<A>] } = dual(2, <A>(self: List<A>, predicate: Predicate<A>): [excluded: List<A>, satisfying: List<A>] => { const left: Array<A> = [] const right: Array<A> = [] for (const a of self) { if (predicate(a)) { right.push(a) } else { left.push(a) } } return [fromIterable(left), fromIterable(right)] }) /** * Partition a list into two lists, where the first list contains all elements * for which the specified function returned a `Left`, and the second list * contains all elements for which the specified function returned a `Right`. * * @since 2.0.0 * @category combinators */ export const partitionMap: { /** * Partition a list into two lists, where the first list contains all elements * for which the specified function returned a `Left`, and the second list * contains all elements for which the specified function returned a `Right`. * * @since 2.0.0 * @category combinators */ <A, B, C>(f: (a: A) => Either.Either<C, B>): (self: List<A>) => [left: List<B>, right: List<C>] /** * Partition a list into two lists, where the first list contains all elements * for which the specified function returned a `Left`, and the second list * contains all elements for which the specified function returned a `Right`. * * @since 2.0.0 * @category combinators */ <A, B, C>(self: List<A>, f: (a: A) => Either.Either<C, B>): [left: List<B>, right: List<C>] } = dual(2, <A, B, C>(self: List<A>, f: (a: A) => Either.Either<C, B>): [left: List<B>, right: List<C>] => { const left: Array<B> = [] const right: Array<C> = [] for (const a of self) { const e = f(a) if (Either.isLeft(e)) { left.push(e.left) } else { right.push(e.right) } } return [fromIterable(left), fromIterable(right)] }) /** * Folds over the elements of the list using the specified function, using the * specified initial value. * * @since 2.0.0 * @category folding */ export const reduce: { /** * Folds over the elements of the list using the specified function, using the * specified initial value. * * @since 2.0.0 * @category folding */ <Z, A>(zero: Z, f: (b: Z, a: A) => Z): (self: List<A>) => Z /** * Folds over the elements of the list using the specified function, using the * specified initial value. * * @since 2.0.0 * @category folding */ <A, Z>(self: List<A>, zero: Z, f: (b: Z, a: A) => Z): Z } = dual(3, <A, Z>(self: List<A>, zero: Z, f: (b: Z, a: A) => Z): Z => { let acc = zero let these = self while (!isNil(these)) { acc = f(acc, these.head) these = these.tail } return acc }) /** * Folds over the elements of the list using the specified function, beginning * with the last element of the list, using the specified initial value. * * @since 2.0.0 * @category folding */ export const reduceRight: { /** * Folds over the elements of the list using the specified function, beginning * with the last element of the list, using the specified initial value. * * @since 2.0.0 * @category folding */ <Z, A>(zero: Z, f: (accumulator: Z, value: A) => Z): (self: List<A>) => Z /** * Folds over the elements of the list using the specified function, beginning * with the last element of the list, using the specified initial value. * * @since 2.0.0 * @category folding */ <Z, A>(self: List<A>, zero: Z, f: (accumulator: Z, value: A) => Z): Z } = dual(3, <Z, A>(self: List<A>, zero: Z, f: (accumulator: Z, value: A) => Z): Z => { let acc = zero let these = reverse(self) while (!isNil(these)) { acc = f(acc, these.head) these = these.tail } return acc }) /** * Returns a new list with the elements of the specified list in reverse order. * * @since 2.0.0 * @category elements */ export const reverse = <A>(self: List<A>): List<A> => { let result = empty<A>() let these = self while (!isNil(these)) { result = prepend(result, these.head) these = these.tail } return result } /** * Splits the specified list into two lists at the specified index. * * @since 2.0.0 * @category combinators */ export const splitAt: { /** * Splits the specified list into two lists at the specified index. * * @since 2.0.0 * @category combinators */ (n: number): <A>(self: List<A>) => [beforeIndex: List<A>, fromIndex: List<A>] /** * Splits the specified list into two lists at the specified index. * * @since 2.0.0 * @category combinators */ <A>(self: List<A>, n: number): [beforeIndex: List<A>, fromIndex: List<A>] } = dual(2, <A>(self: List<A>, n: number): [List<A>, List<A>] => [take(self, n), drop(self, n)]) /** * Returns the tail of the specified list, or `None` if the list is empty. * * @since 2.0.0 * @category getters */ export const tail = <A>(self: List<A>): Option.Option<List<A>> => isNil(self) ? Option.none() : Option.some(self.tail) /** * Takes the specified number of elements from the beginning of the specified * list. * * @since 2.0.0 * @category combinators */ export const take: { /** * Takes the specified number of elements from the beginning of the specified * list. * * @since 2.0.0 * @category combinators */ (n: number): <A>(self: List<A>) => List<A> /** * Takes the specified number of elements from the beginning of the specified * list. * * @since 2.0.0 * @category combinators */ <A>(self: List<A>, n: number): List<A> } = dual(2, <A>(self: List<A>, n: number): List<A> => { if (n <= 0) { return _Nil } if (n >= size(self)) { return self } let these = make(unsafeHead(self)) let current = unsafeTail(self)! for (let i = 1; i < n; i++) { these = makeCons(unsafeHead(current), these) current = unsafeTail(current!) } return reverse(these) }) /** * Converts the specified `List` to a `Chunk`. * * @since 2.0.0 * @category conversions */ export const toChunk = <A>(self: List<A>): Chunk.Chunk<A> => Chunk.fromIterable(self) const getExpectedListToBeNonEmptyErrorMessage = "Expected List to be non-empty" /** * Unsafely returns the first element of the specified `List`. * * @since 2.0.0 * @category unsafe */ export const unsafeHead = <A>(self: List<A>): A => { if (isNil(self)) { throw new Error(getExpectedListToBeNonEmptyErrorMessage) } return self.head } /** * Unsafely returns the last element of the specified `List`. * * @since 2.0.0 * @category unsafe */ export const unsafeLast = <A>(self: List<A>): A => { if (isNil(self)) { throw new Error(getExpectedListToBeNonEmptyErrorMessage) } let these = self let scout = self.tail while (!isNil(scout)) { these = scout scout = scout.tail } return these.head } /** * Unsafely returns the tail of the specified `List`. * * @since 2.0.0 * @category unsafe */ export const unsafeTail = <A>(self: List<A>): List<A> => { if (isNil(self)) { throw new Error(getExpectedListToBeNonEmptyErrorMessage) } return self.tail }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ssv445/lorem-ipsum-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server