1/**
2 * Stores many values in an immutable ordered collection.
3 *
4 * A `Chunk<A>` is useful when you need to build or transform collections
5 * without changing the original collection. It is designed for efficient
6 * append, prepend, and concatenation. This module includes helpers for
7 * creating, reading, slicing, mapping, filtering, sorting, zipping, combining,
8 * and converting chunks to and from arrays and iterables.
9 *
10 * @since 2.0.0
11 */
12import * as RA from "./Array.ts"
13import type { NonEmptyReadonlyArray } from "./Array.ts"
14import * as Equal from "./Equal.ts"
15import * as Equivalence from "./Equivalence.ts"
16import type * as Filter from "./Filter.ts"
17import { format } from "./Formatter.ts"
18import { dual, identity, pipe } from "./Function.ts"
19import * as Hash from "./Hash.ts"
20import type { TypeLambda } from "./HKT.ts"
21import { type Inspectable, NodeInspectSymbol, toJson } from "./Inspectable.ts"
22import * as Count from "./internal/count.ts"
23import type { NonEmptyIterable } from "./NonEmptyIterable.ts"
24import type { Option } from "./Option.ts"
25import * as O from "./Option.ts"
26import * as Order from "./Order.ts"
27import type { Pipeable } from "./Pipeable.ts"
28import { pipeArguments } from "./Pipeable.ts"
29import { hasProperty, type Predicate, type Refinement } from "./Predicate.ts"
30import * as R from "./Result.ts"
31import type { Result } from "./Result.ts"
32import type { Covariant, NoInfer } from "./Types.ts"
33
34const TypeId = "~effect/Chunk"
35
36/**
37 * A Chunk is an immutable, ordered collection optimized for efficient concatenation and access patterns.
38 *
39 * **Example** (Inspecting chunk values)
40 *
41 * ```ts import.meta.vitest
42 * import { Chunk } from "effect"
43 *
44 * const chunk: Chunk.Chunk<number> = Chunk.make(1, 2, 3)
45 * chunk.length // => 3
46 * Chunk.toArray(chunk) // => [1, 2, 3]
47 * ```
48 *
49 * @category models
50 * @since 2.0.0
51 */
52export interface Chunk<out A> extends Iterable<A>, Equal.Equal, Pipeable, Inspectable {
53 readonly [TypeId]: {
54 readonly _A: Covariant<A>
55 }
56 readonly length: number
57 right: Chunk<A>
58 left: Chunk<A>
59 backing: Backing<A>
60 depth: number
61}
62
63/**
64 * A non-empty Chunk guaranteed to contain at least one element.
65 *
66 * **Example** (Working with non-empty chunks)
67 *
68 * ```ts import.meta.vitest
69 * import { Chunk } from "effect"
70 *
71 * const nonEmptyChunk: Chunk.NonEmptyChunk<number> = Chunk.make(1, 2, 3)
72 * Chunk.headNonEmpty(nonEmptyChunk) // => 1
73 * Chunk.lastNonEmpty(nonEmptyChunk) // => 3
74 * ```
75 *
76 * @category models
77 * @since 2.0.0
78 */
79export interface NonEmptyChunk<out A> extends Chunk<A>, NonEmptyIterable<A> {}
80
81/**
82 * Type lambda for Chunk, used for higher-kinded type operations.
83 *
84 * **Example** (Applying the Chunk type lambda)
85 *
86 * ```ts import.meta.vitest
87 * import type { Chunk, HKT } from "effect"
88 *
89 * // Create a Chunk type using the type lambda
90 * type NumberChunk = HKT.Kind<Chunk.ChunkTypeLambda, never, never, never, number>
91 * // Equivalent to: Chunk<number>
92 * ```
93 *
94 * @category utility types
95 * @since 2.0.0
96 */
97export interface ChunkTypeLambda extends TypeLambda {
98 readonly type: Chunk<this["Target"]>
99}
100
101type Backing<A> =
102 | IArray<A>
103 | IConcat<A>
104 | ISingleton<A>
105 | IEmpty
106 | ISlice<A>
107
108interface IArray<A> {
109 readonly _tag: "IArray"
110 readonly array: ReadonlyArray<A>
111}
112
113interface IConcat<A> {
114 readonly _tag: "IConcat"
115 readonly left: Chunk<A>
116 readonly right: Chunk<A>
117}
118
119interface ISingleton<A> {
120 readonly _tag: "ISingleton"
121 readonly a: A
122}
123
124interface IEmpty {
125 readonly _tag: "IEmpty"
126}
127
128interface ISlice<A> {
129 readonly _tag: "ISlice"
130 readonly chunk: Chunk<A>
131 readonly offset: number
132 readonly length: number
133}
134
135function copy<A>(
136 src: ReadonlyArray<A>,
137 srcPos: number,
138 dest: Array<A>,
139 destPos: number,
140 len: number
141) {
142 for (let i = srcPos; i < Math.min(src.length, srcPos + len); i++) {
143 dest[destPos + i - srcPos] = src[i]!
144 }
145 return dest
146}
147
148const emptyArray: ReadonlyArray<never> = []
149
150/**
151 * Creates an `Equivalence` for chunks that compares chunk lengths and then
152 * compares corresponding elements with the provided element equivalence.
153 *
154 * **Example** (Comparing chunks for equivalence)
155 *
156 * ```ts import.meta.vitest
157 * import { Chunk, Equivalence } from "effect"
158 *
159 * const chunk1 = Chunk.make(1, 2, 3)
160 * const chunk2 = Chunk.make(1, 2, 3)
161 * const chunk3 = Chunk.make(1, 2, 4)
162 *
163 * const eq = Chunk.makeEquivalence(Equivalence.strictEqual<number>())
164 * eq(chunk1, chunk2) // => true
165 * eq(chunk1, chunk3) // => false
166 * ```
167 *
168 * @category instances
169 * @since 4.0.0
170 */
171export const makeEquivalence = <A>(isEquivalent: Equivalence.Equivalence<A>): Equivalence.Equivalence<Chunk<A>> =>
172 Equivalence.make((self, that) => {
173 if (self.length !== that.length) {
174 return false
175 }
176 const as = toReadonlyArray(self)
177 const bs = toReadonlyArray(that)
178 for (let i = 0; i < as.length; i++) {
179 if (!isEquivalent(as[i], bs[i])) {
180 return false
181 }
182 }
183 return true
184 })
185
186const _equivalence = makeEquivalence(Equal.equals)
187
188const ChunkProto: Omit<Chunk<unknown>, "backing" | "depth" | "left" | "length" | "right"> = {
189 [TypeId]: {
190 _A: (_: never) => _
191 },
192 toString<A>(this: Chunk<A>) {
193 return `Chunk(${format(toReadonlyArray(this))})`
194 },
195 toJSON<A>(this: Chunk<A>) {
196 return {
197 _id: "Chunk",
198 values: toJson(toReadonlyArray(this))
199 }
200 },
201 [NodeInspectSymbol]<A>(this: Chunk<A>) {
202 return this.toJSON()
203 },
204 [Equal.symbol]<A>(this: Chunk<A>, that: unknown): boolean {
205 return isChunk(that) && _equivalence(this, that)
206 },
207 [Hash.symbol]<A>(this: Chunk<A>): number {
208 return Hash.array(toReadonlyArray(this))
209 },
210 [Symbol.iterator]<A>(this: Chunk<A>): Iterator<A> {
211 switch (this.backing._tag) {
212 case "IArray": {
213 return this.backing.array[Symbol.iterator]()
214 }
215 case "IEmpty": {
216 return emptyArray[Symbol.iterator]()
217 }
218 default: {
219 return toReadonlyArray(this)[Symbol.iterator]()
220 }
221 }
222 },
223 pipe<A>(this: Chunk<A>) {
224 return pipeArguments(this, arguments)
225 }
226}
227
228const makeChunk = <A>(backing: Backing<A>): Chunk<A> => {
229 const chunk = Object.create(ChunkProto)
230 chunk.backing = backing
231 switch (backing._tag) {
232 case "IEmpty": {
233 chunk.length = 0
234 chunk.depth = 0
235 chunk.left = chunk
236 chunk.right = chunk
237 break
238 }
239 case "IConcat": {
240 chunk.length = backing.left.length + backing.right.length
241 chunk.depth = 1 + Math.max(backing.left.depth, backing.right.depth)
242 chunk.left = backing.left
243 chunk.right = backing.right
244 break
245 }
246 case "IArray": {
247 chunk.length = backing.array.length
248 chunk.depth = 0
249 chunk.left = _empty
250 chunk.right = _empty
251 break
252 }
253 case "ISingleton": {
254 chunk.length = 1
255 chunk.depth = 0
256 chunk.left = _empty
257 chunk.right = _empty
258 break
259 }
260 case "ISlice": {
261 chunk.length = backing.length
262 chunk.depth = 0
263 chunk.left = _empty
264 chunk.right = _empty
265 break
266 }
267 }
268 return chunk
269}
270
271/**
272 * Checks whether `u` is a `Chunk<unknown>`
273 *
274 * **Example** (Checking for chunks)
275 *
276 * ```ts import.meta.vitest
277 * import { Chunk } from "effect"
278 *
279 * const chunk = Chunk.make(1, 2, 3)
280 * const array = [1, 2, 3]
281 *
282 * Chunk.isChunk(chunk) // => true
283 * Chunk.isChunk(array) // => false
284 * Chunk.isChunk("string") // => false
285 * ```
286 *
287 * @category guards
288 * @since 2.0.0
289 */
290export const isChunk: {
291 <A>(u: Iterable<A>): u is Chunk<A>
292 (u: unknown): u is Chunk<unknown>
293} = (u: unknown): u is Chunk<unknown> => hasProperty(u, TypeId)
294
295const _empty = makeChunk<never>({ _tag: "IEmpty" })
296
297/**
298 * Creates an empty `Chunk`.
299 *
300 * **Example** (Creating an empty chunk)
301 *
302 * ```ts import.meta.vitest
303 * import { Chunk } from "effect"
304 *
305 * Chunk.size(Chunk.empty()) // => 0
306 * ```
307 *
308 * @category constructors
309 * @since 2.0.0
310 */
311export const empty: <A = never>() => Chunk<A> = () => _empty
312
313/**
314 * Builds a `NonEmptyChunk` from an non-empty collection of elements.
315 *
316 * **Example** (Creating a non-empty chunk)
317 *
318 * ```ts import.meta.vitest
319 * import { Chunk } from "effect"
320 *
321 * Chunk.toArray(Chunk.make(1, 2, 3, 4)) // => [1, 2, 3, 4]
322 * ```
323 *
324 * @category constructors
325 * @since 2.0.0
326 */
327export const make = <As extends readonly [any, ...Array<any>]>(...as: As): NonEmptyChunk<As[number]> =>
328 fromNonEmptyArrayUnsafe(as)
329
330/**
331 * Builds a `NonEmptyChunk` from a single element.
332 *
333 * **Example** (Creating a single-element chunk)
334 *
335 * ```ts import.meta.vitest
336 * import { Chunk } from "effect"
337 *
338 * Chunk.toArray(Chunk.of("hello")) // => ["hello"]
339 * ```
340 *
341 * @category constructors
342 * @since 2.0.0
343 */
344export const of = <A>(a: A): NonEmptyChunk<A> => makeChunk({ _tag: "ISingleton", a }) as any
345
346/**
347 * Creates a new `Chunk` from an iterable collection of values.
348 *
349 * **Example** (Creating chunks from iterables)
350 *
351 * ```ts import.meta.vitest
352 * import { Chunk } from "effect"
353 *
354 * Chunk.toArray(Chunk.fromIterable([1, 2, 3])) // => [1, 2, 3]
355 * ```
356 *
357 * @category constructors
358 * @since 2.0.0
359 */
360export const fromIterable = <A>(self: Iterable<A>): Chunk<A> =>
361 isChunk(self) ? self : fromArrayUnsafe(RA.fromIterable(self))
362
363const copyToArray = <A>(self: Chunk<A>, array: Array<any>, initial: number): void => {
364 switch (self.backing._tag) {
365 case "IArray": {
366 copy(self.backing.array, 0, array, initial, self.length)
367 break
368 }
369 case "IConcat": {
370 copyToArray(self.left, array, initial)
371 copyToArray(self.right, array, initial + self.left.length)
372 break
373 }
374 case "ISingleton": {
375 array[initial] = self.backing.a
376 break
377 }
378 case "ISlice": {
379 copy(toReadonlyArray(self.backing.chunk), self.backing.offset, array, initial, self.length)
380 break
381 }
382 }
383}
384
385const toArray_ = <A>(self: Chunk<A>): Array<A> => toReadonlyArray(self).slice()
386
387/**
388 * Converts a `Chunk` into an `Array`. If the provided `Chunk` is non-empty
389 * (`NonEmptyChunk`), the function will return a `NonEmptyArray`, ensuring the
390 * non-empty property is preserved.
391 *
392 * **Example** (Converting chunks to mutable arrays)
393 *
394 * ```ts import.meta.vitest
395 * import { Chunk } from "effect"
396 *
397 * const chunk = Chunk.make(1, 2, 3)
398 * const array = Chunk.toArray(chunk)
399 * array // => [1, 2, 3]
400 * Array.isArray(array) // => true
401 *
402 * // With empty chunk
403 * Chunk.toArray(Chunk.empty<number>()) // => []
404 * ```
405 *
406 * @category converting
407 * @since 2.0.0
408 */
409export const toArray: <S extends Chunk<any>>(
410 self: S
411) => S extends NonEmptyChunk<any> ? RA.NonEmptyArray<Chunk.Infer<S>> : Array<Chunk.Infer<S>> = toArray_ as any
412
413const toReadonlyArray_ = <A>(self: Chunk<A>): ReadonlyArray<A> => {
414 switch (self.backing._tag) {
415 case "IEmpty": {
416 return emptyArray
417 }
418 case "IArray": {
419 return self.backing.array
420 }
421 default: {
422 const arr = new Array<A>(self.length)
423 copyToArray(self, arr, 0)
424 self.backing = {
425 _tag: "IArray",
426 array: arr
427 }
428 self.left = _empty
429 self.right = _empty
430 self.depth = 0
431 return arr
432 }
433 }
434}
435
436/**
437 * Converts a `Chunk` into a `ReadonlyArray`. If the provided `Chunk` is
438 * non-empty (`NonEmptyChunk`), the function will return a
439 * `NonEmptyReadonlyArray`, ensuring the non-empty property is preserved.
440 *
441 * **Example** (Converting chunks to readonly arrays)
442 *
443 * ```ts import.meta.vitest
444 * import { Chunk } from "effect"
445 *
446 * const chunk = Chunk.make(1, 2, 3)
447 * const readonlyArray = Chunk.toReadonlyArray(chunk)
448 * readonlyArray // => [1, 2, 3]
449 *
450 * // The result is read-only, modifications would cause TypeScript errors
451 * // readonlyArray[0] = 10 // TypeScript error
452 *
453 * // With empty chunk
454 * Chunk.toReadonlyArray(Chunk.empty<number>()) // => []
455 * ```
456 *
457 * @category converting
458 * @since 2.0.0
459 */
460export const toReadonlyArray: <S extends Chunk<any>>(
461 self: S
462) => S extends NonEmptyChunk<any> ? RA.NonEmptyReadonlyArray<Chunk.Infer<S>> : ReadonlyArray<Chunk.Infer<S>> =
463 toReadonlyArray_ as any
464
465const reverseChunk = <A>(self: Chunk<A>): Chunk<A> => {
466 switch (self.backing._tag) {
467 case "IEmpty":
468 case "ISingleton":
469 return self
470 case "IArray": {
471 return makeChunk({ _tag: "IArray", array: RA.reverse(self.backing.array) })
472 }
473 case "IConcat": {
474 return makeChunk({ _tag: "IConcat", left: reverse(self.backing.right), right: reverse(self.backing.left) })
475 }
476 case "ISlice":
477 return fromArrayUnsafe(RA.reverse(toReadonlyArray(self)))
478 }
479}
480
481/**
482 * Reverses the order of elements in a `Chunk`.
483 *
484 * **When to use**
485 *
486 * Use to read or process chunk elements in reverse order.
487 *
488 * **Details**
489 *
490 * If the input chunk is a `NonEmptyChunk`, the reversed chunk is also a
491 * `NonEmptyChunk`.
492 *
493 * **Example** (Reversing chunks)
494 *
495 * ```ts import.meta.vitest
496 * import { Chunk } from "effect"
497 *
498 * const chunk = Chunk.make(1, 2, 3)
499 * Chunk.toArray(Chunk.reverse(chunk)) // => [3, 2, 1]
500 * ```
501 *
502 * @category transforming
503 * @since 2.0.0
504 */
505export const reverse: <S extends Chunk<any>>(self: S) => Chunk.With<S, Chunk.Infer<S>> = reverseChunk as any
506
507/**
508 * Gets the value at an index in a `Chunk` safely, returning `None` when the index is
509 * out of bounds.
510 *
511 * **Example** (Accessing elements safely)
512 *
513 * ```ts import.meta.vitest
514 * import { Chunk, Option } from "effect"
515 *
516 * const chunk = Chunk.make("a", "b", "c", "d")
517 *
518 * Chunk.get(chunk, 1) // => Option.some("b")
519 * Chunk.get(chunk, 10) // => Option.none()
520 * Chunk.get(chunk, -1) // => Option.none()
521 *
522 * // Using pipe syntax
523 * chunk.pipe(Chunk.get(2)) // => Option.some("c")
524 * ```
525 *
526 * @category getters
527 * @since 2.0.0
528 */
529export const get: {
530 (index: number): <A>(self: Chunk<A>) => Option<A>
531 <A>(self: Chunk<A>, index: number): Option<A>
532} = dual(
533 2,
534 <A>(self: Chunk<A>, index: number): Option<A> =>
535 index < 0 || index >= self.length ? O.none() : O.some(getUnsafe(self, index))
536)
537
538/**
539 * Wraps an array into a chunk without copying.
540 *
541 * **When to use**
542 *
543 * Use when the input array can be shared with the resulting `Chunk` and avoiding
544 * a copy matters.
545 *
546 * **Gotchas**
547 *
548 * Mutating the source array after wrapping can mutate the resulting `Chunk`.
549 *
550 * **Example** (Creating chunks without copying arrays)
551 *
552 * ```ts import.meta.vitest
553 * import { Chunk } from "effect"
554 *
555 * const array = [1, 2, 3, 4, 5]
556 * const chunk = Chunk.fromArrayUnsafe(array)
557 * Chunk.toArray(chunk) // => [1, 2, 3, 4, 5]
558 *
559 * // Warning: Since this doesn't copy the array, mutations affect the chunk
560 * array[0] = 999
561 * Chunk.toArray(chunk) // => [999, 2, 3, 4, 5]
562 * ```
563 *
564 * @category unsafe
565 * @since 4.0.0
566 */
567export const fromArrayUnsafe = <A>(self: ReadonlyArray<A>): Chunk<A> =>
568 self.length === 0 ? empty() : self.length === 1 ? of(self[0]) : makeChunk({ _tag: "IArray", array: self })
569
570/**
571 * Wraps a non-empty array into a non-empty chunk without copying.
572 *
573 * **When to use**
574 *
575 * Use when the input array is already known to be non-empty, can be shared with
576 * the resulting `Chunk`, and avoiding a copy matters.
577 *
578 * **Gotchas**
579 *
580 * Mutating the source array after wrapping can mutate the resulting `Chunk`.
581 *
582 * **Example** (Creating non-empty chunks without copying arrays)
583 *
584 * ```ts import.meta.vitest
585 * import { Array, Chunk } from "effect"
586 *
587 * const nonEmptyArray = Array.make(1, 2, 3, 4, 5)
588 * const chunk = Chunk.fromNonEmptyArrayUnsafe(nonEmptyArray)
589 * Chunk.toArray(chunk) // => [1, 2, 3, 4, 5]
590 *
591 * // The result is guaranteed to be non-empty
592 * Chunk.isNonEmpty(chunk) // => true
593 * ```
594 *
595 * @category unsafe
596 * @since 4.0.0
597 */
598export const fromNonEmptyArrayUnsafe = <A>(self: NonEmptyReadonlyArray<A>): NonEmptyChunk<A> =>
599 fromArrayUnsafe(self) as any
600
601/**
602 * Gets an element at the specified index without returning an `Option`.
603 *
604 * **When to use**
605 *
606 * Use when reading from a `Chunk` at an index known to be in bounds and direct
607 * element access is preferred over handling `Option.none`.
608 *
609 * **Gotchas**
610 *
611 * Throws if the index is out of bounds.
612 *
613 * **Example** (Accessing elements unsafely)
614 *
615 * ```ts import.meta.vitest
616 * import { Chunk, Option } from "effect"
617 *
618 * const chunk = Chunk.make("a", "b", "c", "d")
619 *
620 * Chunk.getUnsafe(chunk, 1) // => "b"
621 * Chunk.getUnsafe(chunk, 3) // => "d"
622 *
623 * // Use Chunk.get when the index may be out of bounds
624 * Option.isNone(Chunk.get(chunk, 10)) // => true
625 * ```
626 *
627 * @category unsafe
628 * @since 4.0.0
629 */
630export const getUnsafe: {
631 (index: number): <A>(self: Chunk<A>) => A
632 <A>(self: Chunk<A>, index: number): A
633} = dual(2, <A>(self: Chunk<A>, index: number): A => {
634 const i = Math.floor(index)
635 switch (self.backing._tag) {
636 case "IEmpty": {
637 throw new Error(`Index out of bounds: ${i}`)
638 }
639 case "ISingleton": {
640 if (index !== 0) {
641 throw new Error(`Index out of bounds: ${i}`)
642 }
643 return self.backing.a
644 }
645 case "IArray": {
646 if (i >= self.length || i < 0) {
647 throw new Error(`Index out of bounds: ${i}`)
648 }
649 return self.backing.array[i]!
650 }
651 case "IConcat": {
652 return i < self.left.length
653 ? getUnsafe(self.left, i)
654 : getUnsafe(self.right, i - self.left.length)
655 }
656 case "ISlice": {
657 return getUnsafe(self.backing.chunk, i + self.backing.offset)
658 }
659 }
660})
661
662/**
663 * Appends the specified element to the end of the `Chunk`.
664 *
665 * **When to use**
666 *
667 * Use to add one element after the existing chunk elements and return a
668 * `NonEmptyChunk`.
669 *
670 * **Example** (Appending an element)
671 *
672 * ```ts import.meta.vitest
673 * import { Chunk } from "effect"
674 *
675 * const chunk = Chunk.make(1, 2, 3)
676 * Chunk.toArray(Chunk.append(chunk, 4)) // => [1, 2, 3, 4]
677 *
678 * // Appending to empty chunk
679 * const emptyChunk = Chunk.empty<number>()
680 * Chunk.toArray(Chunk.append(emptyChunk, 42)) // => [42]
681 * ```
682 *
683 * @see {@link prepend} for adding one element before the existing elements
684 * @see {@link appendAll} for appending all elements from another chunk
685 *
686 * @category combining
687 * @since 2.0.0
688 */
689export const append: {
690 <A2>(a: A2): <A>(self: Chunk<A>) => NonEmptyChunk<A2 | A>
691 <A, A2>(self: Chunk<A>, a: A2): NonEmptyChunk<A | A2>
692} = dual(2, <A, A2>(self: Chunk<A>, a: A2): NonEmptyChunk<A | A2> => appendAll(self, of(a)))
693
694/**
695 * Prepends an element to the front of a `Chunk`, creating a new `NonEmptyChunk`.
696 *
697 * **Example** (Prepending an element)
698 *
699 * ```ts import.meta.vitest
700 * import { Chunk } from "effect"
701 *
702 * const chunk = Chunk.make(2, 3, 4)
703 * Chunk.toArray(Chunk.prepend(chunk, 1)) // => [1, 2, 3, 4]
704 *
705 * // Prepending to empty chunk
706 * const emptyChunk = Chunk.empty<string>()
707 * Chunk.toArray(Chunk.prepend(emptyChunk, "first")) // => ["first"]
708 * ```
709 *
710 * @category combining
711 * @since 2.0.0
712 */
713export const prepend: {
714 <B>(elem: B): <A>(self: Chunk<A>) => NonEmptyChunk<B | A>
715 <A, B>(self: Chunk<A>, elem: B): NonEmptyChunk<A | B>
716} = dual(2, <A, B>(self: Chunk<A>, elem: B): NonEmptyChunk<A | B> => appendAll(of(elem), self))
717
718/**
719 * Takes the first up to `n` elements from the chunk.
720 * `n` is rounded down, with `NaN` and non-positive values treated as `0`.
721 *
722 * **Example** (Taking elements from the start)
723 *
724 * ```ts import.meta.vitest
725 * import { Chunk } from "effect"
726 *
727 * const chunk = Chunk.make(1, 2, 3, 4, 5)
728 * Chunk.toArray(Chunk.take(chunk, 3)) // => [1, 2, 3]
729 * ```
730 *
731 * @category filtering
732 * @since 2.0.0
733 */
734export const take: {
735 (n: number): <A>(self: Chunk<A>) => Chunk<A>
736 <A>(self: Chunk<A>, n: number): Chunk<A>
737} = dual(2, <A>(self: Chunk<A>, _n: number): Chunk<A> => {
738 const n = Count.normalize(_n)
739 if (n <= 0) {
740 return _empty
741 } else if (n >= self.length) {
742 return self
743 } else {
744 switch (self.backing._tag) {
745 case "ISlice": {
746 return makeChunk({
747 _tag: "ISlice",
748 chunk: self.backing.chunk,
749 length: n,
750 offset: self.backing.offset
751 })
752 }
753 case "IConcat": {
754 if (n > self.left.length) {
755 return makeChunk({
756 _tag: "IConcat",
757 left: self.left,
758 right: take(self.right, n - self.left.length)
759 })
760 }
761
762 return take(self.left, n)
763 }
764 default: {
765 return makeChunk({
766 _tag: "ISlice",
767 chunk: self,
768 offset: 0,
769 length: n
770 })
771 }
772 }
773 }
774})
775
776/**
777 * Drops the first up to `n` elements from the chunk.
778 * `n` is rounded down, with `NaN` and non-positive values treated as `0`.
779 *
780 * **Example** (Dropping elements from the start)
781 *
782 * ```ts import.meta.vitest
783 * import { Chunk } from "effect"
784 *
785 * const chunk = Chunk.make(1, 2, 3, 4, 5)
786 * Chunk.toArray(Chunk.drop(chunk, 2)) // => [3, 4, 5]
787 * ```
788 *
789 * @category filtering
790 * @since 2.0.0
791 */
792export const drop: {
793 (n: number): <A>(self: Chunk<A>) => Chunk<A>
794 <A>(self: Chunk<A>, n: number): Chunk<A>
795} = dual(2, <A>(self: Chunk<A>, _n: number): Chunk<A> => {
796 const n = Count.normalize(_n)
797 if (n <= 0) {
798 return self
799 } else if (n >= self.length) {
800 return _empty
801 } else {
802 switch (self.backing._tag) {
803 case "ISlice": {
804 return makeChunk({
805 _tag: "ISlice",
806 chunk: self.backing.chunk,
807 offset: self.backing.offset + n,
808 length: self.backing.length - n
809 })
810 }
811 case "IConcat": {
812 if (n > self.left.length) {
813 return drop(self.right, n - self.left.length)
814 }
815 return makeChunk({
816 _tag: "IConcat",
817 left: drop(self.left, n),
818 right: self.right
819 })
820 }
821 default: {
822 return makeChunk({
823 _tag: "ISlice",
824 chunk: self,
825 offset: n,
826 length: self.length - n
827 })
828 }
829 }
830 }
831})
832
833/**
834 * Drops the last `n` elements.
835 * `n` is rounded down, with `NaN` and non-positive values treated as `0`.
836 *
837 * **Example** (Dropping elements from the end)
838 *
839 * ```ts import.meta.vitest
840 * import { Chunk } from "effect"
841 *
842 * const chunk = Chunk.make(1, 2, 3, 4, 5)
843 * Chunk.toArray(Chunk.dropRight(chunk, 2)) // => [1, 2, 3]
844 * ```
845 *
846 * @category filtering
847 * @since 2.0.0
848 */
849export const dropRight: {
850 (n: number): <A>(self: Chunk<A>) => Chunk<A>
851 <A>(self: Chunk<A>, n: number): Chunk<A>
852} = dual(
853 2,
854 <A>(self: Chunk<A>, n: number): Chunk<A> => take(self, self.length - Math.min(Count.normalize(n), self.length))
855)
856
857/**
858 * Drops all elements so long as the predicate returns true.
859 *
860 * **Example** (Dropping elements while a predicate matches)
861 *
862 * ```ts import.meta.vitest
863 * import { Chunk } from "effect"
864 *
865 * const chunk = Chunk.make(1, 2, 3, 4, 5)
866 * Chunk.toArray(Chunk.dropWhile(chunk, (n) => n < 3)) // => [3, 4, 5]
867 * ```
868 *
869 * @category filtering
870 * @since 2.0.0
871 */
872export const dropWhile: {
873 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => Chunk<A>
874 <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A>
875} = dual(2, <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A> => {
876 const arr = toReadonlyArray(self)
877 const len = arr.length
878 let i = 0
879 while (i < len && predicate(arr[i]!)) {
880 i++
881 }
882 return drop(self, i)
883})
884
885/**
886 * Prepends the specified prefix chunk to the beginning of the specified chunk.
887 * If either chunk is non-empty, the result is also a non-empty chunk.
888 *
889 * **Example** (Prepending all elements)
890 *
891 * ```ts import.meta.vitest
892 * import { Chunk } from "effect"
893 *
894 * Chunk.make(1, 2).pipe(
895 * Chunk.prependAll(Chunk.make("a", "b")),
896 * Chunk.toArray
897 * ) // => ["a", "b", 1, 2]
898 * ```
899 *
900 * @category combining
901 * @since 2.0.0
902 */
903export const prependAll: {
904 <S extends Chunk<any>, T extends Chunk<any>>(
905 that: T
906 ): (self: S) => Chunk.OrNonEmpty<S, T, Chunk.Infer<S> | Chunk.Infer<T>>
907 <A, B>(self: Chunk<A>, that: NonEmptyChunk<B>): NonEmptyChunk<A | B>
908 <A, B>(self: NonEmptyChunk<A>, that: Chunk<B>): NonEmptyChunk<A | B>
909 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A | B>
910} = dual(2, <A, B>(self: NonEmptyChunk<A>, that: Chunk<B>): Chunk<A | B> => appendAll(that, self))
911
912/**
913 * Concatenates two chunks, combining their elements.
914 * If either chunk is non-empty, the result is also a non-empty chunk.
915 *
916 * **When to use**
917 *
918 * Use to concatenate two chunks when the second chunk's elements should come
919 * after the first.
920 *
921 * **Example** (Appending all elements)
922 *
923 * ```ts import.meta.vitest
924 * import { Chunk } from "effect"
925 *
926 * Chunk.make(1, 2).pipe(
927 * Chunk.appendAll(Chunk.make("a", "b")),
928 * Chunk.toArray
929 * ) // => [1, 2, "a", "b"]
930 * ```
931 *
932 * @see {@link prependAll} for concatenating chunks in the opposite order
933 * @see {@link append} for adding a single element to the end
934 *
935 * @category combining
936 * @since 2.0.0
937 */
938export const appendAll: {
939 <S extends Chunk<any>, T extends Chunk<any>>(
940 that: T
941 ): (self: S) => Chunk.OrNonEmpty<S, T, Chunk.Infer<S> | Chunk.Infer<T>>
942 <A, B>(self: Chunk<A>, that: NonEmptyChunk<B>): NonEmptyChunk<A | B>
943 <A, B>(self: NonEmptyChunk<A>, that: Chunk<B>): NonEmptyChunk<A | B>
944 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A | B>
945} = dual(2, <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A | B> => {
946 if (self.backing._tag === "IEmpty") {
947 return that
948 }
949 if (that.backing._tag === "IEmpty") {
950 return self
951 }
952 const diff = that.depth - self.depth
953 if (Math.abs(diff) <= 1) {
954 return makeChunk<A | B>({ _tag: "IConcat", left: self, right: that })
955 } else if (diff < -1) {
956 if (self.left.depth >= self.right.depth) {
957 const nr = appendAll(self.right, that)
958 return makeChunk({ _tag: "IConcat", left: self.left, right: nr })
959 } else {
960 const nrr = appendAll(self.right.right, that)
961 if (nrr.depth === self.depth - 3) {
962 const nr = makeChunk({ _tag: "IConcat", left: self.right.left, right: nrr })
963 return makeChunk({ _tag: "IConcat", left: self.left, right: nr })
964 } else {
965 const nl = makeChunk({ _tag: "IConcat", left: self.left, right: self.right.left })
966 return makeChunk({ _tag: "IConcat", left: nl, right: nrr })
967 }
968 }
969 } else {
970 if (that.right.depth >= that.left.depth) {
971 const nl = appendAll(self, that.left)
972 return makeChunk({ _tag: "IConcat", left: nl, right: that.right })
973 } else {
974 const nll = appendAll(self, that.left.left)
975 if (nll.depth === that.depth - 3) {
976 const nl = makeChunk({ _tag: "IConcat", left: nll, right: that.left.right })
977 return makeChunk({ _tag: "IConcat", left: nl, right: that.right })
978 } else {
979 const nr = makeChunk({ _tag: "IConcat", left: that.left.right, right: that.right })
980 return makeChunk({ _tag: "IConcat", left: nll, right: nr })
981 }
982 }
983 }
984})
985
986/**
987 * Returns a filtered and mapped subset of the elements.
988 *
989 * **Example** (Filtering and mapping values)
990 *
991 * ```ts import.meta.vitest
992 * import { Chunk, Result } from "effect"
993 *
994 * const chunk = Chunk.make("1", "2", "hello", "3", "world")
995 * const numbers = Chunk.filterMap(chunk, (str) => {
996 * const num = parseInt(str)
997 * return isNaN(num) ? Result.failVoid : Result.succeed(num)
998 * })
999 * Chunk.toArray(numbers) // => [1, 2, 3]
1000 *
1001 * // With index parameter
1002 * const evenIndexNumbers = Chunk.filterMap(chunk, (str, i) => {
1003 * const num = parseInt(str)
1004 * return isNaN(num) || i % 2 !== 0 ? Result.failVoid : Result.succeed(num)
1005 * })
1006 * Chunk.toArray(evenIndexNumbers) // => [1]
1007 * ```
1008 *
1009 * @category filtering
1010 * @since 2.0.0
1011 */
1012export const filterMap: {
1013 <A, B, X>(f: (input: A, i: number) => Result<B, X>): (self: Chunk<A>) => Chunk<B>
1014 <A, B, X>(self: Chunk<A>, f: (input: A, i: number) => Result<B, X>): Chunk<B>
1015} = dual(
1016 2,
1017 <A, B, X>(self: Chunk<A>, f: (input: A, i: number) => Result<B, X>): Chunk<B> => {
1018 const as = toReadonlyArray(self)
1019 const out: Array<B> = []
1020 for (let i = 0; i < as.length; i++) {
1021 const result = f(as[i], i)
1022 if (R.isSuccess(result)) {
1023 out.push(result.success)
1024 }
1025 }
1026 return fromArrayUnsafe(out)
1027 }
1028)
1029
1030/**
1031 * Returns a filtered subset of the elements.
1032 *
1033 * **Example** (Filtering values)
1034 *
1035 * ```ts import.meta.vitest
1036 * import { Chunk } from "effect"
1037 *
1038 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6)
1039 * const evenNumbers = Chunk.filter(chunk, (n) => n % 2 === 0)
1040 * Chunk.toArray(evenNumbers) // => [2, 4, 6]
1041 *
1042 * // With refinement
1043 * const mixed = Chunk.make("hello", 42, "world", 100)
1044 * const numbers = Chunk.filter(mixed, (x): x is number => typeof x === "number")
1045 * Chunk.toArray(numbers) // => [42, 100]
1046 * ```
1047 *
1048 * @category filtering
1049 * @since 2.0.0
1050 */
1051export const filter: {
1052 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Chunk<A>) => Chunk<B>
1053 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => Chunk<A>
1054 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): Chunk<B>
1055 <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A>
1056} = dual(
1057 2,
1058 <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A> => fromArrayUnsafe(RA.filter(toReadonlyArray(self), predicate))
1059)
1060
1061/**
1062 * Transforms all elements of the chunk for as long as the specified function succeeds.
1063 *
1064 * **Example** (Filtering and mapping while values match)
1065 *
1066 * ```ts import.meta.vitest
1067 * import { Chunk, Result } from "effect"
1068 *
1069 * const chunk = Chunk.make("1", "2", "hello", "3", "4")
1070 * Chunk.toArray(Chunk.filterMapWhile(chunk, (s) => {
1071 * const n = Number(s)
1072 * return Number.isNaN(n) ? Result.failVoid : Result.succeed(n)
1073 * })) // => [1, 2]
1074 *
1075 * Chunk.toArray(Chunk.filterMap(chunk, (s) => {
1076 * const n = Number(s)
1077 * return Number.isNaN(n) ? Result.failVoid : Result.succeed(n)
1078 * })) // => [1, 2, 3, 4]
1079 * ```
1080 *
1081 * @category filtering
1082 * @since 2.0.0
1083 */
1084export const filterMapWhile: {
1085 <A, B, X>(f: Filter.Filter<A, B, X>): (self: Chunk<A>) => Chunk<B>
1086 <A, B, X>(self: Chunk<A>, f: Filter.Filter<A, B, X>): Chunk<B>
1087} = dual(2, <A, B, X>(self: Chunk<A>, f: Filter.Filter<A, B, X>): Chunk<B> => {
1088 const out: Array<B> = []
1089 for (const a of self) {
1090 const result = f(a)
1091 if (R.isSuccess(result)) {
1092 out.push(result.success)
1093 } else {
1094 break
1095 }
1096 }
1097 return fromArrayUnsafe(out)
1098})
1099
1100/**
1101 * Filters out optional values
1102 *
1103 * **Example** (Compacting optional values)
1104 *
1105 * ```ts import.meta.vitest
1106 * import { Chunk, Option } from "effect"
1107 *
1108 * const chunk = Chunk.make(Option.some(1), Option.none(), Option.some(3))
1109 * Chunk.toArray(Chunk.compact(chunk)) // => [1, 3]
1110 * ```
1111 *
1112 * @category filtering
1113 * @since 2.0.0
1114 */
1115export const compact = <A>(self: Chunk<Option<A>>): Chunk<A> => {
1116 const out: Array<A> = []
1117 for (const option of self) {
1118 if (O.isSome(option)) {
1119 out.push(option.value)
1120 }
1121 }
1122 return fromArrayUnsafe(out)
1123}
1124
1125/**
1126 * Applies a function to each element in a chunk and returns a new chunk containing the concatenated mapped elements.
1127 *
1128 * **Example** (Flat mapping chunks)
1129 *
1130 * ```ts import.meta.vitest
1131 * import { Chunk } from "effect"
1132 *
1133 * const chunk = Chunk.make(1, 2, 3)
1134 * const duplicated = Chunk.flatMap(chunk, (n) => Chunk.make(n, n))
1135 * Chunk.toArray(duplicated) // => [1, 1, 2, 2, 3, 3]
1136 *
1137 * // Flattening nested arrays
1138 * const words = Chunk.make("hello", "world")
1139 * const letters = Chunk.flatMap(
1140 * words,
1141 * (word) => Chunk.fromIterable(word.split(""))
1142 * )
1143 * Chunk.toArray(letters).join("") // => "helloworld"
1144 *
1145 * // With index parameter
1146 * const indexed = Chunk.flatMap(chunk, (n, i) => Chunk.make(n + i))
1147 * Chunk.toArray(indexed) // => [1, 3, 5]
1148 * ```
1149 *
1150 * @category sequencing
1151 * @since 2.0.0
1152 */
1153export const flatMap: {
1154 <S extends Chunk<any>, T extends Chunk<any>>(
1155 f: (a: Chunk.Infer<S>, i: number) => T
1156 ): (self: S) => Chunk.AndNonEmpty<S, T, Chunk.Infer<T>>
1157 <A, B>(self: NonEmptyChunk<A>, f: (a: A, i: number) => NonEmptyChunk<B>): NonEmptyChunk<B>
1158 <A, B>(self: Chunk<A>, f: (a: A, i: number) => Chunk<B>): Chunk<B>
1159} = dual(2, <A, B>(self: Chunk<A>, f: (a: A, i: number) => Chunk<B>) => {
1160 if (self.backing._tag === "ISingleton") {
1161 return f(self.backing.a, 0)
1162 }
1163 const as = toReadonlyArray(self)
1164 const chunks = new Array<Chunk<B>>(as.length)
1165 for (let i = 0; i < as.length; i++) {
1166 chunks[i] = f(as[i], i)
1167 }
1168 for (let step = 1; step < chunks.length; step *= 2) {
1169 for (let i = 0; i + step < chunks.length; i += 2 * step) {
1170 chunks[i] = appendAll(chunks[i], chunks[i + step])
1171 }
1172 }
1173 return chunks.length === 0 ? _empty : chunks[0]
1174})
1175
1176/**
1177 * Iterates over each element of a `Chunk` and applies a function to it.
1178 *
1179 * **Details**
1180 *
1181 * This function processes every element of the given `Chunk`, calling the
1182 * provided function `f` on each element. It does not return a new value;
1183 * instead, it is primarily used for side effects, such as logging or
1184 * accumulating data in an external variable.
1185 *
1186 * **Example** (Iterating over chunk values)
1187 *
1188 * ```ts import.meta.vitest
1189 * import { Chunk } from "effect"
1190 *
1191 * const chunk = Chunk.make(1, 2, 3, 4)
1192 *
1193 * const values: Array<string> = []
1194 * Chunk.forEach(chunk, (n) => values.push(`Value: ${n}`))
1195 * values // => ["Value: 1", "Value: 2", "Value: 3", "Value: 4"]
1196 *
1197 * // With index parameter
1198 * const indexed: Array<string> = []
1199 * Chunk.forEach(chunk, (n, i) => indexed.push(`Index ${i}: ${n}`))
1200 * indexed // => ["Index 0: 1", "Index 1: 2", "Index 2: 3", "Index 3: 4"]
1201 * ```
1202 *
1203 * @category combinators
1204 * @since 2.0.0
1205 */
1206export const forEach: {
1207 <A, B>(f: (a: A, index: number) => B): (self: Chunk<A>) => void
1208 <A, B>(self: Chunk<A>, f: (a: A, index: number) => B): void
1209} = dual(2, <A, B>(self: Chunk<A>, f: (a: A) => B): void => toReadonlyArray(self).forEach(f))
1210
1211/**
1212 * Flattens a chunk of chunks into a single chunk by concatenating all chunks.
1213 *
1214 * **Example** (Flattening nested chunks)
1215 *
1216 * ```ts import.meta.vitest
1217 * import { Chunk } from "effect"
1218 *
1219 * const nested = Chunk.make(
1220 * Chunk.make(1, 2),
1221 * Chunk.make(3, 4, 5),
1222 * Chunk.make(6)
1223 * )
1224 * Chunk.toArray(Chunk.flatten(nested)) // => [1, 2, 3, 4, 5, 6]
1225 *
1226 * // With empty chunks
1227 * const withEmpty = Chunk.make(
1228 * Chunk.make(1, 2),
1229 * Chunk.empty<number>(),
1230 * Chunk.make(3, 4)
1231 * )
1232 * Chunk.toArray(Chunk.flatten(withEmpty)) // => [1, 2, 3, 4]
1233 * ```
1234 *
1235 * @category sequencing
1236 * @since 2.0.0
1237 */
1238export const flatten: <S extends Chunk<Chunk<any>>>(self: S) => Chunk.Flatten<S> = flatMap(identity) as any
1239
1240/**
1241 * Groups elements in chunks of up to `n` elements.
1242 *
1243 * **When to use**
1244 *
1245 * Use to divide a chunk into ordered, non-overlapping chunks with at most `n`
1246 * elements each.
1247 *
1248 * **Details**
1249 *
1250 * `n` is rounded down and normalized to at least `1`. The final chunk may
1251 * contain fewer than `n` elements. Empty input produces an empty chunk of
1252 * chunks.
1253 *
1254 * **Gotchas**
1255 *
1256 * `NaN` and values of `n` less than or equal to zero produce singleton chunks.
1257 *
1258 * **Example** (Splitting into fixed-size chunks)
1259 *
1260 * ```ts import.meta.vitest
1261 * import { Chunk } from "effect"
1262 *
1263 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8, 9)
1264 * const chunked = Chunk.chunksOf(chunk, 3)
1265 *
1266 * Chunk.toArray(chunked).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1267 *
1268 * // When length is not evenly divisible
1269 * const chunk2 = Chunk.make(1, 2, 3, 4, 5)
1270 * const chunked2 = Chunk.chunksOf(chunk2, 2)
1271 * Chunk.toArray(chunked2).map(Chunk.toArray) // => [[1, 2], [3, 4], [5]]
1272 * ```
1273 *
1274 * @see {@link split} for splitting into a target number of chunks instead of a fixed chunk size
1275 *
1276 * @category splitting
1277 * @since 2.0.0
1278 */
1279export const chunksOf: {
1280 (n: number): <A>(self: Chunk<A>) => Chunk<Chunk<A>>
1281 <A>(self: Chunk<A>, n: number): Chunk<Chunk<A>>
1282} = dual(2, <A>(self: Chunk<A>, n: number) => {
1283 const size = Count.normalizeNonEmpty(n)
1284 const gr: Array<Chunk<A>> = []
1285 let current: Array<A> = []
1286 toReadonlyArray(self).forEach((a) => {
1287 current.push(a)
1288 if (current.length >= size) {
1289 gr.push(fromArrayUnsafe(current))
1290 current = []
1291 }
1292 })
1293 if (current.length > 0) {
1294 gr.push(fromArrayUnsafe(current))
1295 }
1296 return fromArrayUnsafe(gr)
1297})
1298
1299/**
1300 * Creates a `Chunk` of values that are included in both chunks.
1301 *
1302 * **Details**
1303 *
1304 * The order and references of result values are determined by the first chunk.
1305 *
1306 * **Example** (Intersecting chunks)
1307 *
1308 * ```ts import.meta.vitest
1309 * import { Chunk } from "effect"
1310 *
1311 * const chunk1 = Chunk.make(1, 2, 3, 4)
1312 * const chunk2 = Chunk.make(3, 4, 5, 6)
1313 * Chunk.toArray(Chunk.intersection(chunk1, chunk2)) // => [3, 4]
1314 *
1315 * // With strings
1316 * const words1 = Chunk.make("hello", "world", "foo")
1317 * const words2 = Chunk.make("world", "bar", "foo")
1318 * Chunk.toArray(Chunk.intersection(words1, words2)) // => ["world", "foo"]
1319 *
1320 * // No intersection
1321 * const chunk3 = Chunk.make(1, 2)
1322 * const chunk4 = Chunk.make(3, 4)
1323 * Chunk.toArray(Chunk.intersection(chunk3, chunk4)) // => []
1324 * ```
1325 *
1326 * @category set operations
1327 * @since 2.0.0
1328 */
1329export const intersection: {
1330 <A>(that: Chunk<A>): <B>(self: Chunk<B>) => Chunk<A & B>
1331 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A & B>
1332} = dual(
1333 2,
1334 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A & B> =>
1335 fromArrayUnsafe(RA.intersection(toReadonlyArray(self), toReadonlyArray(that)))
1336)
1337
1338/**
1339 * Determines if the chunk is empty.
1340 *
1341 * **Example** (Checking for empty chunks)
1342 *
1343 * ```ts import.meta.vitest
1344 * import { Chunk } from "effect"
1345 *
1346 * Chunk.isEmpty(Chunk.empty()) // => true
1347 * Chunk.isEmpty(Chunk.make(1, 2, 3)) // => false
1348 * ```
1349 *
1350 * @category predicates
1351 * @since 2.0.0
1352 */
1353export const isEmpty = <A>(self: Chunk<A>): boolean => self.length === 0
1354
1355/**
1356 * Determines if the chunk is not empty.
1357 *
1358 * **Example** (Checking for non-empty chunks)
1359 *
1360 * ```ts import.meta.vitest
1361 * import { Chunk } from "effect"
1362 *
1363 * Chunk.isNonEmpty(Chunk.empty()) // => false
1364 * Chunk.isNonEmpty(Chunk.make(1, 2, 3)) // => true
1365 * ```
1366 *
1367 * @category guards
1368 * @since 2.0.0
1369 */
1370export const isNonEmpty = <A>(self: Chunk<A>): self is NonEmptyChunk<A> => self.length > 0
1371
1372/**
1373 * Returns the first element of this chunk safely if it exists.
1374 *
1375 * **Example** (Getting the first element)
1376 *
1377 * ```ts import.meta.vitest
1378 * import { Chunk, Option } from "effect"
1379 *
1380 * Chunk.head(Chunk.empty()) // => Option.none()
1381 * Chunk.head(Chunk.make(1, 2, 3)) // => Option.some(1)
1382 * ```
1383 *
1384 * @category getters
1385 * @since 2.0.0
1386 */
1387export const head: <A>(self: Chunk<A>) => Option<A> = get(0)
1388
1389/**
1390 * Returns the first element of this chunk.
1391 *
1392 * **When to use**
1393 *
1394 * Use when you know the chunk is non-empty and need the first element directly
1395 * without handling `Option.none`.
1396 *
1397 * **Gotchas**
1398 *
1399 * Throws an error if the chunk is empty.
1400 *
1401 * **Example** (Getting the first element unsafely)
1402 *
1403 * ```ts import.meta.vitest
1404 * import { Chunk, Option } from "effect"
1405 *
1406 * const chunk = Chunk.make(1, 2, 3, 4)
1407 * Chunk.headUnsafe(chunk) // => 1
1408 *
1409 * const singleElement = Chunk.make("hello")
1410 * Chunk.headUnsafe(singleElement) // => "hello"
1411 *
1412 * // Use Chunk.head when the chunk may be empty
1413 * Option.isNone(Chunk.head(Chunk.empty())) // => true
1414 * ```
1415 *
1416 * @category unsafe
1417 * @since 4.0.0
1418 */
1419export const headUnsafe = <A>(self: Chunk<A>): A => getUnsafe(self, 0)
1420
1421/**
1422 * Returns the first element of this non empty chunk.
1423 *
1424 * **Example** (Getting the first element of a non-empty chunk)
1425 *
1426 * ```ts import.meta.vitest
1427 * import { Chunk } from "effect"
1428 *
1429 * const nonEmptyChunk = Chunk.make(1, 2, 3, 4)
1430 * Chunk.headNonEmpty(nonEmptyChunk) // => 1
1431 *
1432 * const singleElement = Chunk.make("hello")
1433 * Chunk.headNonEmpty(singleElement) // => "hello"
1434 *
1435 * // Type safety: this function only accepts NonEmptyChunk
1436 * // Chunk.headNonEmpty(Chunk.empty()) // TypeScript error
1437 * ```
1438 *
1439 * @category getters
1440 * @since 2.0.0
1441 */
1442export const headNonEmpty: <A>(self: NonEmptyChunk<A>) => A = headUnsafe
1443
1444/**
1445 * Returns the last element of this chunk safely if it exists.
1446 *
1447 * **Example** (Getting the last element)
1448 *
1449 * ```ts import.meta.vitest
1450 * import { Chunk, Option } from "effect"
1451 *
1452 * Chunk.last(Chunk.empty()) // => Option.none()
1453 * Chunk.last(Chunk.make(1, 2, 3)) // => Option.some(3)
1454 * ```
1455 *
1456 * @category getters
1457 * @since 2.0.0
1458 */
1459export const last = <A>(self: Chunk<A>): Option<A> => get(self, self.length - 1)
1460
1461/**
1462 * Returns the last element of this chunk.
1463 *
1464 * **When to use**
1465 *
1466 * Use when you know the chunk is non-empty and need the last element directly
1467 * without handling `Option.none`.
1468 *
1469 * **Gotchas**
1470 *
1471 * Throws an error if the chunk is empty.
1472 *
1473 * **Example** (Getting the last element unsafely)
1474 *
1475 * ```ts import.meta.vitest
1476 * import { Chunk, Option } from "effect"
1477 *
1478 * const chunk = Chunk.make(1, 2, 3, 4)
1479 * Chunk.lastUnsafe(chunk) // => 4
1480 *
1481 * const singleElement = Chunk.make("hello")
1482 * Chunk.lastUnsafe(singleElement) // => "hello"
1483 *
1484 * // Use Chunk.last when the chunk may be empty
1485 * Option.isNone(Chunk.last(Chunk.empty())) // => true
1486 * ```
1487 *
1488 * @category unsafe
1489 * @since 4.0.0
1490 */
1491export const lastUnsafe = <A>(self: Chunk<A>): A => getUnsafe(self, self.length - 1)
1492
1493/**
1494 * Returns the last element of this non empty chunk.
1495 *
1496 * **Example** (Getting the last element of a non-empty chunk)
1497 *
1498 * ```ts import.meta.vitest
1499 * import { Chunk } from "effect"
1500 *
1501 * const nonEmptyChunk = Chunk.make(1, 2, 3, 4)
1502 * Chunk.lastNonEmpty(nonEmptyChunk) // => 4
1503 *
1504 * const singleElement = Chunk.make("hello")
1505 * Chunk.lastNonEmpty(singleElement) // => "hello"
1506 *
1507 * // Type safety: this function only accepts NonEmptyChunk
1508 * // Chunk.lastNonEmpty(Chunk.empty()) // TypeScript error
1509 * ```
1510 *
1511 * @category getters
1512 * @since 3.4.0
1513 */
1514export const lastNonEmpty: <A>(self: NonEmptyChunk<A>) => A = lastUnsafe
1515
1516/**
1517 * A namespace containing utility types for Chunk operations.
1518 *
1519 * **Example** (Working with Chunk utility types)
1520 *
1521 * ```ts import.meta.vitest
1522 * import type { Chunk } from "effect"
1523 *
1524 * // Extract the element type from a Chunk
1525 * declare const chunk: Chunk.Chunk<string>
1526 * type ElementType = Chunk.Chunk.Infer<typeof chunk> // string
1527 *
1528 * // Create a preserving non-emptiness
1529 * declare const nonEmptyChunk: Chunk.NonEmptyChunk<number>
1530 * type WithString = Chunk.Chunk.With<typeof nonEmptyChunk, string> // Chunk.NonEmptyChunk<string>
1531 * ```
1532 *
1533 * @since 2.0.0
1534 */
1535export declare namespace Chunk {
1536 /**
1537 * Infers the element type of a Chunk.
1538 *
1539 * **Example** (Inferring element types)
1540 *
1541 * ```ts import.meta.vitest
1542 * import type { Chunk } from "effect"
1543 *
1544 * declare const numberChunk: Chunk.Chunk<number>
1545 * declare const stringChunk: Chunk.Chunk<string>
1546 *
1547 * type NumberType = Chunk.Chunk.Infer<typeof numberChunk> // number
1548 * type StringType = Chunk.Chunk.Infer<typeof stringChunk> // string
1549 * ```
1550 *
1551 * @category utility types
1552 * @since 2.0.0
1553 */
1554 export type Infer<S extends Chunk<any>> = S extends Chunk<infer A> ? A : never
1555
1556 /**
1557 * Constructs a Chunk type preserving non-emptiness.
1558 *
1559 * **Example** (Preserving non-emptiness)
1560 *
1561 * ```ts import.meta.vitest
1562 * import type { Chunk } from "effect"
1563 *
1564 * declare const regularChunk: Chunk.Chunk<number>
1565 * declare const nonEmptyChunk: Chunk.NonEmptyChunk<number>
1566 *
1567 * type WithString1 = Chunk.Chunk.With<typeof regularChunk, string> // Chunk.Chunk<string>
1568 * type WithString2 = Chunk.Chunk.With<typeof nonEmptyChunk, string> // Chunk.NonEmptyChunk<string>
1569 * ```
1570 *
1571 * @category utility types
1572 * @since 2.0.0
1573 */
1574 export type With<S extends Chunk<any>, A> = S extends NonEmptyChunk<any> ? NonEmptyChunk<A> : Chunk<A>
1575
1576 /**
1577 * Creates a non-empty Chunk if either input is non-empty.
1578 *
1579 * **Example** (Preserving non-emptiness from either input)
1580 *
1581 * ```ts import.meta.vitest
1582 * import type { Chunk } from "effect"
1583 *
1584 * declare const emptyChunk: Chunk.Chunk<number>
1585 * declare const nonEmptyChunk: Chunk.NonEmptyChunk<number>
1586 *
1587 * type Result1 = Chunk.Chunk.OrNonEmpty<
1588 * typeof emptyChunk,
1589 * typeof emptyChunk,
1590 * string
1591 * > // Chunk.Chunk<string>
1592 * type Result2 = Chunk.Chunk.OrNonEmpty<
1593 * typeof emptyChunk,
1594 * typeof nonEmptyChunk,
1595 * string
1596 * > // Chunk.NonEmptyChunk<string>
1597 * type Result3 = Chunk.Chunk.OrNonEmpty<
1598 * typeof nonEmptyChunk,
1599 * typeof emptyChunk,
1600 * string
1601 * > // Chunk.NonEmptyChunk<string>
1602 * ```
1603 *
1604 * @category utility types
1605 * @since 2.0.0
1606 */
1607 export type OrNonEmpty<S extends Chunk<any>, T extends Chunk<any>, A> = S extends NonEmptyChunk<any> ?
1608 NonEmptyChunk<A>
1609 : T extends NonEmptyChunk<any> ? NonEmptyChunk<A>
1610 : Chunk<A>
1611
1612 /**
1613 * Creates a non-empty Chunk only if both inputs are non-empty.
1614 *
1615 * **Example** (Requiring non-emptiness from both inputs)
1616 *
1617 * ```ts import.meta.vitest
1618 * import type { Chunk } from "effect"
1619 *
1620 * declare const emptyChunk: Chunk.Chunk<number>
1621 * declare const nonEmptyChunk: Chunk.NonEmptyChunk<number>
1622 *
1623 * type Result1 = Chunk.Chunk.AndNonEmpty<
1624 * typeof emptyChunk,
1625 * typeof emptyChunk,
1626 * string
1627 * > // Chunk.Chunk<string>
1628 * type Result2 = Chunk.Chunk.AndNonEmpty<
1629 * typeof emptyChunk,
1630 * typeof nonEmptyChunk,
1631 * string
1632 * > // Chunk.Chunk<string>
1633 * type Result3 = Chunk.Chunk.AndNonEmpty<
1634 * typeof nonEmptyChunk,
1635 * typeof nonEmptyChunk,
1636 * string
1637 * > // Chunk.NonEmptyChunk<string>
1638 * ```
1639 *
1640 * @category utility types
1641 * @since 2.0.0
1642 */
1643 export type AndNonEmpty<S extends Chunk<any>, T extends Chunk<any>, A> = S extends NonEmptyChunk<any> ?
1644 T extends NonEmptyChunk<any> ? NonEmptyChunk<A>
1645 : Chunk<A> :
1646 Chunk<A>
1647
1648 /**
1649 * Flattens a nested Chunk type.
1650 *
1651 * **Example** (Flattening nested chunk types)
1652 *
1653 * ```ts import.meta.vitest
1654 * import type { Chunk } from "effect"
1655 *
1656 * declare const nestedChunk: Chunk.Chunk<Chunk.Chunk<number>>
1657 * declare const nestedNonEmpty: Chunk.NonEmptyChunk<Chunk.NonEmptyChunk<string>>
1658 *
1659 * type Flattened1 = Chunk.Chunk.Flatten<typeof nestedChunk> // Chunk.Chunk<number>
1660 * type Flattened2 = Chunk.Chunk.Flatten<typeof nestedNonEmpty> // Chunk.NonEmptyChunk<string>
1661 * ```
1662 *
1663 * @category utility types
1664 * @since 2.0.0
1665 */
1666 export type Flatten<T extends Chunk<Chunk<any>>> = T extends NonEmptyChunk<NonEmptyChunk<infer A>> ? NonEmptyChunk<A>
1667 : T extends Chunk<Chunk<infer A>> ? Chunk<A>
1668 : never
1669}
1670
1671/**
1672 * Transforms the elements of a chunk using the specified mapping function.
1673 * If the input chunk is non-empty, the resulting chunk will also be non-empty.
1674 *
1675 * **Example** (Mapping values)
1676 *
1677 * ```ts import.meta.vitest
1678 * import { Chunk } from "effect"
1679 *
1680 * Chunk.toArray(Chunk.map(Chunk.make(1, 2), (n) => n + 1)) // => [2, 3]
1681 * ```
1682 *
1683 * @category mapping
1684 * @since 2.0.0
1685 */
1686export const map: {
1687 <S extends Chunk<any>, B>(f: (a: Chunk.Infer<S>, i: number) => B): (self: S) => Chunk.With<S, B>
1688 <A, B>(self: NonEmptyChunk<A>, f: (a: A, i: number) => B): NonEmptyChunk<B>
1689 <A, B>(self: Chunk<A>, f: (a: A, i: number) => B): Chunk<B>
1690} = dual(2, <A, B>(self: Chunk<A>, f: (a: A, i: number) => B): Chunk<B> =>
1691 self.backing._tag === "ISingleton" ?
1692 of(f(self.backing.a, 0)) :
1693 fromArrayUnsafe(pipe(toReadonlyArray(self), RA.map((a, i) => f(a, i)))))
1694
1695/**
1696 * Maps over the chunk statefully, producing new elements of type `B`.
1697 *
1698 * **Example** (Mapping with accumulated state)
1699 *
1700 * ```ts import.meta.vitest
1701 * import { Chunk } from "effect"
1702 *
1703 * const chunk = Chunk.make(1, 2, 3, 4, 5)
1704 * const [finalState, mapped] = Chunk.mapAccum(chunk, 0, (state, current) => [
1705 * state + current, // accumulate sum
1706 * state + current // output running sum
1707 * ])
1708 *
1709 * finalState // => 15
1710 * Chunk.toArray(mapped) // => [1, 3, 6, 10, 15]
1711 *
1712 * // Building a string with indices
1713 * const words = Chunk.make("hello", "world", "effect")
1714 * const [count, indexed] = Chunk.mapAccum(words, 0, (index, word) => [
1715 * index + 1,
1716 * `${index}: ${word}`
1717 * ])
1718 * count // => 3
1719 * Chunk.toArray(indexed) // => ["0: hello", "1: world", "2: effect"]
1720 * ```
1721 *
1722 * @category folding
1723 * @since 2.0.0
1724 */
1725export const mapAccum: {
1726 <S, A, B>(s: S, f: (s: S, a: A) => readonly [S, B]): (self: Chunk<A>) => [S, Chunk<B>]
1727 <S, A, B>(self: Chunk<A>, s: S, f: (s: S, a: A) => readonly [S, B]): [S, Chunk<B>]
1728} = dual(3, <S, A, B>(self: Chunk<A>, s: S, f: (s: S, a: A) => readonly [S, B]): [S, Chunk<B>] => {
1729 const [s1, as] = RA.mapAccum(self, s, f)
1730 return [s1, fromArrayUnsafe(as)]
1731})
1732
1733/**
1734 * Splits a chunk using a `Filter` into successes and failures.
1735 *
1736 * **Details**
1737 *
1738 * Returns `[passes, fails]`. The filter receives `(element, index)`.
1739 *
1740 * **Example** (Partitioning with a Result)
1741 *
1742 * ```ts import.meta.vitest
1743 * import { Chunk, Result } from "effect"
1744 *
1745 * const [passes, fails] = Chunk.partition(Chunk.make(1, -2, 3), (n, i) =>
1746 * n > 0 ? Result.succeed(n + i) : Result.fail(`negative:${n}`)
1747 * )
1748 *
1749 * Chunk.toArray(passes) // => [1, 5]
1750 * Chunk.toArray(fails) // => ["negative:-2"]
1751 * ```
1752 *
1753 * @category filtering
1754 * @since 2.0.0
1755 */
1756export const partition: {
1757 <A, Pass, Fail>(
1758 f: (input: NoInfer<A>, i: number) => Result<Pass, Fail>
1759 ): (self: Chunk<A>) => [passes: Chunk<Pass>, fails: Chunk<Fail>]
1760 <A, Pass, Fail>(
1761 self: Chunk<A>,
1762 f: (input: A, i: number) => Result<Pass, Fail>
1763 ): [passes: Chunk<Pass>, fails: Chunk<Fail>]
1764} = dual(
1765 2,
1766 <A, Pass, Fail>(
1767 self: Chunk<A>,
1768 f: (input: A, i: number) => Result<Pass, Fail>
1769 ): [passes: Chunk<Pass>, fails: Chunk<Fail>] => {
1770 const [passes, fails] = RA.partition(self, f)
1771 return [fromArrayUnsafe(passes), fromArrayUnsafe(fails)]
1772 }
1773)
1774
1775/**
1776 * Separates a chunk of `Result` values into a chunk of successes and a chunk of
1777 * failures.
1778 *
1779 * **Details**
1780 *
1781 * The returned tuple is `[successes, failures]`, preserving the original order
1782 * within each side.
1783 *
1784 * **Example** (Separating successes and failures)
1785 *
1786 * ```ts import.meta.vitest
1787 * import { Chunk, Result } from "effect"
1788 *
1789 * const chunk = Chunk.make(
1790 * Result.succeed(1),
1791 * Result.fail("error1"),
1792 * Result.succeed(2),
1793 * Result.fail("error2"),
1794 * Result.succeed(3)
1795 * )
1796 *
1797 * const [values, errors] = Chunk.separate(chunk)
1798 * Chunk.toArray(values) // => [1, 2, 3]
1799 * Chunk.toArray(errors) // => ["error1", "error2"]
1800 *
1801 * // All successes
1802 * const allSuccesses = Chunk.make(Result.succeed(1), Result.succeed(2))
1803 * const [allValues, noErrors] = Chunk.separate(allSuccesses)
1804 * Chunk.toArray(allValues) // => [1, 2]
1805 * Chunk.toArray(noErrors) // => []
1806 * ```
1807 *
1808 * @category filtering
1809 * @since 2.0.0
1810 */
1811export const separate = <A, B>(self: Chunk<Result<B, A>>): [Chunk<B>, Chunk<A>] =>
1812 pipe(
1813 RA.separate(toReadonlyArray(self)),
1814 ([l, r]) => [fromArrayUnsafe(l), fromArrayUnsafe(r)]
1815 )
1816
1817/**
1818 * Retrieves the size of the chunk.
1819 *
1820 * **Example** (Getting chunk size)
1821 *
1822 * ```ts import.meta.vitest
1823 * import { Chunk } from "effect"
1824 *
1825 * Chunk.size(Chunk.make(1, 2, 3)) // => 3
1826 * ```
1827 *
1828 * @category getters
1829 * @since 2.0.0
1830 */
1831export const size = <A>(self: Chunk<A>): number => self.length
1832
1833/**
1834 * Sorts the elements of a `Chunk` in increasing order, creating a new `Chunk`.
1835 *
1836 * **Example** (Sorting chunks)
1837 *
1838 * ```ts import.meta.vitest
1839 * import { Chunk, Order } from "effect"
1840 *
1841 * const numbers = Chunk.make(3, 1, 4, 1, 5, 9, 2, 6)
1842 * Chunk.toArray(Chunk.sort(numbers, Order.Number)) // => [1, 1, 2, 3, 4, 5, 6, 9]
1843 *
1844 * // Reverse order
1845 * Chunk.toArray(Chunk.sort(numbers, Order.flip(Order.Number))) // => [9, 6, 5, 4, 3, 2, 1, 1]
1846 *
1847 * // String sorting
1848 * const words = Chunk.make("banana", "apple", "cherry")
1849 * Chunk.toArray(Chunk.sort(words, Order.String)) // => ["apple", "banana", "cherry"]
1850 * ```
1851 *
1852 * @category sorting
1853 * @since 2.0.0
1854 */
1855export const sort: {
1856 <B>(O: Order.Order<B>): <A extends B>(self: Chunk<A>) => Chunk<A>
1857 <A extends B, B>(self: Chunk<A>, O: Order.Order<B>): Chunk<A>
1858} = dual(
1859 2,
1860 <A extends B, B>(self: Chunk<A>, O: Order.Order<B>): Chunk<A> => fromArrayUnsafe(RA.sort(toReadonlyArray(self), O))
1861)
1862
1863/**
1864 * Sorts the elements of a `Chunk` based on a projection function.
1865 *
1866 * **Example** (Sorting chunks by a derived value)
1867 *
1868 * ```ts import.meta.vitest
1869 * import { Chunk, Order } from "effect"
1870 *
1871 * const people = Chunk.make(
1872 * { name: "Alice", age: 30 },
1873 * { name: "Bob", age: 25 },
1874 * { name: "Charlie", age: 35 }
1875 * )
1876 *
1877 * // Sort by age
1878 * const byAge = Chunk.sortWith(people, (person) => person.age, Order.Number)
1879 * Chunk.toArray(byAge).map((person) => person.name) // => ["Bob", "Alice", "Charlie"]
1880 *
1881 * // Sort by name
1882 * const byName = Chunk.sortWith(people, (person) => person.name, Order.String)
1883 * Chunk.toArray(byName).map((person) => person.name) // => ["Alice", "Bob", "Charlie"]
1884 *
1885 * // Sort by string length
1886 * const words = Chunk.make("a", "abc", "ab")
1887 * Chunk.toArray(Chunk.sortWith(words, (word) => word.length, Order.Number)) // => ["a", "ab", "abc"]
1888 * ```
1889 *
1890 * @category sorting
1891 * @since 2.0.0
1892 */
1893export const sortWith: {
1894 <A, B>(f: (a: A) => B, order: Order.Order<B>): (self: Chunk<A>) => Chunk<A>
1895 <A, B>(self: Chunk<A>, f: (a: A) => B, order: Order.Order<B>): Chunk<A>
1896} = dual(
1897 3,
1898 <A, B>(self: Chunk<A>, f: (a: A) => B, order: Order.Order<B>): Chunk<A> => sort(self, Order.mapInput(order, f))
1899)
1900
1901/**
1902 * Returns two splits of this chunk at the specified index.
1903 *
1904 * **Example** (Splitting at an index)
1905 *
1906 * ```ts import.meta.vitest
1907 * import { Chunk } from "effect"
1908 *
1909 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6)
1910 * const [before, after] = Chunk.splitAt(chunk, 3)
1911 * Chunk.toArray(before) // => [1, 2, 3]
1912 * Chunk.toArray(after) // => [4, 5, 6]
1913 *
1914 * // Split at index 0
1915 * const [empty, all] = Chunk.splitAt(chunk, 0)
1916 * Chunk.toArray(empty) // => []
1917 * Chunk.toArray(all) // => [1, 2, 3, 4, 5, 6]
1918 *
1919 * // Split beyond length
1920 * const [allElements, empty2] = Chunk.splitAt(chunk, 10)
1921 * Chunk.toArray(allElements) // => [1, 2, 3, 4, 5, 6]
1922 * Chunk.toArray(empty2) // => []
1923 * ```
1924 *
1925 * @category splitting
1926 * @since 2.0.0
1927 */
1928export const splitAt: {
1929 (n: number): <A>(self: Chunk<A>) => [beforeIndex: Chunk<A>, fromIndex: Chunk<A>]
1930 <A>(self: Chunk<A>, n: number): [beforeIndex: Chunk<A>, fromIndex: Chunk<A>]
1931} = dual(2, <A>(self: Chunk<A>, n: number): [Chunk<A>, Chunk<A>] => [take(self, n), drop(self, n)])
1932
1933/**
1934 * Splits a `NonEmptyChunk` at `n`, returning a non-empty prefix and the
1935 * remaining suffix.
1936 *
1937 * **Details**
1938 *
1939 * `n` is rounded down and normalized to at least `1`, with `NaN` treated as
1940 * `1`. If `n` is greater than or equal to the chunk length, the first result is
1941 * the original chunk and the second result is empty.
1942 *
1943 * **Example** (Splitting non-empty chunks at an index)
1944 *
1945 * ```ts import.meta.vitest
1946 * import { Chunk } from "effect"
1947 *
1948 * const nonEmptyChunk = Chunk.make(1, 2, 3, 4, 5, 6)
1949 * const [before, after] = Chunk.splitNonEmptyAt(nonEmptyChunk, 3)
1950 * Chunk.toArray(before) // => [1, 2, 3]
1951 * Chunk.toArray(after) // => [4, 5, 6]
1952 *
1953 * // Split at 1 (minimum)
1954 * const [first, rest] = Chunk.splitNonEmptyAt(nonEmptyChunk, 1)
1955 * Chunk.toArray(first) // => [1]
1956 * Chunk.toArray(rest) // => [2, 3, 4, 5, 6]
1957 *
1958 * // The first part is guaranteed to be NonEmptyChunk
1959 * // while the second part may be empty
1960 * ```
1961 *
1962 * @category splitting
1963 * @since 2.0.0
1964 */
1965export const splitNonEmptyAt: {
1966 (n: number): <A>(self: NonEmptyChunk<A>) => [beforeIndex: NonEmptyChunk<A>, fromIndex: Chunk<A>]
1967 <A>(self: NonEmptyChunk<A>, n: number): [beforeIndex: NonEmptyChunk<A>, fromIndex: Chunk<A>]
1968} = dual(2, <A>(self: NonEmptyChunk<A>, n: number): [Chunk<A>, Chunk<A>] => {
1969 const _n = Count.normalizeNonEmpty(n)
1970 return _n >= self.length ?
1971 [self, empty()] :
1972 [take(self, _n), drop(self, _n)]
1973})
1974
1975/**
1976 * Splits a chunk into up to `n` chunks, distributing elements in order.
1977 *
1978 * **Details**
1979 *
1980 * `n` is rounded down and normalized to at least `1`, with `NaN` treated as
1981 * `1`. The chunk size is derived from the input length and normalized count;
1982 * the final chunk may contain fewer elements than the others.
1983 *
1984 * **Example** (Splitting chunks into groups)
1985 *
1986 * ```ts import.meta.vitest
1987 * import { Chunk } from "effect"
1988 *
1989 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8, 9)
1990 * const chunks = Chunk.split(chunk, 3)
1991 * Chunk.toArray(chunks).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1992 *
1993 * // Uneven split
1994 * const chunk2 = Chunk.make(1, 2, 3, 4, 5, 6, 7, 8)
1995 * const chunks2 = Chunk.split(chunk2, 3)
1996 * Chunk.toArray(chunks2).map(Chunk.toArray) // => [[1, 2, 3], [4, 5, 6], [7, 8]]
1997 *
1998 * // Split into 1 chunk
1999 * const chunks3 = Chunk.split(chunk, 1)
2000 * Chunk.toArray(chunks3).map(Chunk.toArray) // => [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
2001 * ```
2002 *
2003 * @category splitting
2004 * @since 2.0.0
2005 */
2006export const split: {
2007 (n: number): <A>(self: Chunk<A>) => Chunk<Chunk<A>>
2008 <A>(self: Chunk<A>, n: number): Chunk<Chunk<A>>
2009} = dual(2, <A>(self: Chunk<A>, n: number) => chunksOf(self, Math.ceil(self.length / Count.normalizeNonEmpty(n))))
2010
2011/**
2012 * Splits this chunk on the first element that matches this predicate.
2013 * Returns a tuple containing two chunks: the first one is before the match, and the second one is from the match onward.
2014 *
2015 * **Example** (Splitting at a matching element)
2016 *
2017 * ```ts import.meta.vitest
2018 * import { Chunk } from "effect"
2019 *
2020 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6)
2021 * const [before, fromMatch] = Chunk.splitWhere(chunk, (n) => n > 3)
2022 * Chunk.toArray(before) // => [1, 2, 3]
2023 * Chunk.toArray(fromMatch) // => [4, 5, 6]
2024 *
2025 * // No match found
2026 * const [all, empty] = Chunk.splitWhere(chunk, (n) => n > 10)
2027 * Chunk.toArray(all) // => [1, 2, 3, 4, 5, 6]
2028 * Chunk.toArray(empty) // => []
2029 *
2030 * // Match on first element
2031 * const [emptyBefore, allFromFirst] = Chunk.splitWhere(chunk, (n) => n === 1)
2032 * Chunk.toArray(emptyBefore) // => []
2033 * Chunk.toArray(allFromFirst) // => [1, 2, 3, 4, 5, 6]
2034 * ```
2035 *
2036 * @category splitting
2037 * @since 2.0.0
2038 */
2039export const splitWhere: {
2040 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => [beforeMatch: Chunk<A>, fromMatch: Chunk<A>]
2041 <A>(self: Chunk<A>, predicate: Predicate<A>): [beforeMatch: Chunk<A>, fromMatch: Chunk<A>]
2042} = dual(2, <A>(self: Chunk<A>, predicate: Predicate<A>): [beforeMatch: Chunk<A>, fromMatch: Chunk<A>] => {
2043 let i = 0
2044 for (const a of toReadonlyArray(self)) {
2045 if (predicate(a)) {
2046 break
2047 } else {
2048 i++
2049 }
2050 }
2051 return splitAt(self, i)
2052})
2053
2054/**
2055 * Returns every element after the first safely, or `None` when the chunk is empty.
2056 *
2057 * **Example** (Getting the tail safely)
2058 *
2059 * ```ts import.meta.vitest
2060 * import { Chunk, Option } from "effect"
2061 *
2062 * const chunk = Chunk.make(1, 2, 3, 4)
2063 * Chunk.tail(chunk) // => Option.some(Chunk.make(2, 3, 4))
2064 *
2065 * const singleElement = Chunk.make(1)
2066 * Chunk.tail(singleElement) // => Option.some(Chunk.empty())
2067 *
2068 * Chunk.tail(Chunk.empty<number>()) // => Option.none()
2069 * ```
2070 *
2071 * @category getters
2072 * @since 2.0.0
2073 */
2074export const tail = <A>(self: Chunk<A>): O.Option<Chunk<A>> => self.length > 0 ? O.some(drop(self, 1)) : O.none()
2075
2076/**
2077 * Returns every element after the first from a non-empty chunk.
2078 *
2079 * **Example** (Getting the tail of a non-empty chunk)
2080 *
2081 * ```ts import.meta.vitest
2082 * import { Chunk } from "effect"
2083 *
2084 * const nonEmptyChunk = Chunk.make(1, 2, 3, 4)
2085 * Chunk.toArray(Chunk.tailNonEmpty(nonEmptyChunk)) // => [2, 3, 4]
2086 *
2087 * const singleElement = Chunk.make(1)
2088 * Chunk.toArray(Chunk.tailNonEmpty(singleElement)) // => []
2089 *
2090 * // Type safety: this function only accepts NonEmptyChunk
2091 * // Chunk.tailNonEmpty(Chunk.empty()) // TypeScript error
2092 * ```
2093 *
2094 * @category getters
2095 * @since 2.0.0
2096 */
2097export const tailNonEmpty = <A>(self: NonEmptyChunk<A>): Chunk<A> => drop(self, 1)
2098
2099/**
2100 * Takes the last `n` elements.
2101 * `n` is rounded down, with `NaN` and non-positive values treated as `0`.
2102 *
2103 * **Example** (Taking elements from the end)
2104 *
2105 * ```ts import.meta.vitest
2106 * import { Chunk } from "effect"
2107 *
2108 * const chunk = Chunk.make(1, 2, 3, 4, 5, 6)
2109 * Chunk.toArray(Chunk.takeRight(chunk, 3)) // => [4, 5, 6]
2110 *
2111 * // Take more than available
2112 * Chunk.toArray(Chunk.takeRight(chunk, 10)) // => [1, 2, 3, 4, 5, 6]
2113 *
2114 * // Take zero
2115 * Chunk.toArray(Chunk.takeRight(chunk, 0)) // => []
2116 * ```
2117 *
2118 * @category filtering
2119 * @since 2.0.0
2120 */
2121export const takeRight: {
2122 (n: number): <A>(self: Chunk<A>) => Chunk<A>
2123 <A>(self: Chunk<A>, n: number): Chunk<A>
2124} = dual(
2125 2,
2126 <A>(self: Chunk<A>, n: number): Chunk<A> => drop(self, self.length - Math.min(Count.normalize(n), self.length))
2127)
2128
2129/**
2130 * Takes all elements so long as the predicate returns true.
2131 *
2132 * **Example** (Taking elements while a predicate matches)
2133 *
2134 * ```ts import.meta.vitest
2135 * import { Chunk } from "effect"
2136 *
2137 * const chunk = Chunk.make(1, 2, 3, 4, 3, 2, 1)
2138 * Chunk.toArray(Chunk.takeWhile(chunk, (n) => n < 4)) // => [1, 2, 3]
2139 *
2140 * // Empty if first element doesn't match
2141 * Chunk.toArray(Chunk.takeWhile(chunk, (n) => n > 5)) // => []
2142 *
2143 * // Takes all if all match
2144 * const small = Chunk.make(1, 2, 3)
2145 * Chunk.toArray(Chunk.takeWhile(small, (n) => n < 10)) // => [1, 2, 3]
2146 * ```
2147 *
2148 * @category filtering
2149 * @since 2.0.0
2150 */
2151export const takeWhile: {
2152 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Chunk<A>) => Chunk<B>
2153 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => Chunk<A>
2154 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): Chunk<B>
2155 <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A>
2156} = dual(2, <A>(self: Chunk<A>, predicate: Predicate<A>): Chunk<A> => {
2157 const out: Array<A> = []
2158 for (const a of toReadonlyArray(self)) {
2159 if (predicate(a)) {
2160 out.push(a)
2161 } else {
2162 break
2163 }
2164 }
2165 return fromArrayUnsafe(out)
2166})
2167
2168/**
2169 * Creates a Chunks of unique values, in order, from all given Chunks.
2170 *
2171 * **Example** (Unioning chunks)
2172 *
2173 * ```ts import.meta.vitest
2174 * import { Chunk } from "effect"
2175 *
2176 * const chunk1 = Chunk.make(1, 2, 3)
2177 * const chunk2 = Chunk.make(3, 4, 5)
2178 * Chunk.toArray(Chunk.union(chunk1, chunk2)) // => [1, 2, 3, 4, 5]
2179 *
2180 * // Handles duplicates within the same chunk
2181 * const withDupes1 = Chunk.make(1, 1, 2)
2182 * const withDupes2 = Chunk.make(2, 3, 3)
2183 * Chunk.toArray(Chunk.union(withDupes1, withDupes2)) // => [1, 2, 3]
2184 * ```
2185 *
2186 * @category set operations
2187 * @since 2.0.0
2188 */
2189export const union: {
2190 <A>(that: Chunk<A>): <B>(self: Chunk<B>) => Chunk<A | B>
2191 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<A | B>
2192} = dual(
2193 2,
2194 <A, B>(self: Chunk<A>, that: Chunk<B>) => fromArrayUnsafe(RA.union(toReadonlyArray(self), toReadonlyArray(that)))
2195)
2196
2197/**
2198 * Removes duplicate elements from a `Chunk`, preserving the first occurrence
2199 * of each value.
2200 *
2201 * **Example** (Removing duplicate values)
2202 *
2203 * ```ts import.meta.vitest
2204 * import { Chunk } from "effect"
2205 *
2206 * const chunk = Chunk.make(1, 2, 2, 3, 1, 4, 3)
2207 * Chunk.toArray(Chunk.dedupe(chunk)) // => [1, 2, 3, 4]
2208 *
2209 * // Empty chunk
2210 * const empty = Chunk.empty<number>()
2211 * Chunk.toArray(Chunk.dedupe(empty)) // => []
2212 *
2213 * // No duplicates
2214 * const unique = Chunk.make(1, 2, 3)
2215 * Chunk.toArray(Chunk.dedupe(unique)) // => [1, 2, 3]
2216 * ```
2217 *
2218 * @category deduplication
2219 * @since 2.0.0
2220 */
2221export const dedupe = <A>(self: Chunk<A>): Chunk<A> => fromArrayUnsafe(RA.dedupe(toReadonlyArray(self)))
2222
2223/**
2224 * Deduplicates adjacent elements that are identical.
2225 *
2226 * **Example** (Removing adjacent duplicates)
2227 *
2228 * ```ts import.meta.vitest
2229 * import { Chunk } from "effect"
2230 *
2231 * const chunk = Chunk.make(1, 1, 2, 2, 2, 3, 1, 1)
2232 * Chunk.toArray(Chunk.dedupeAdjacent(chunk)) // => [1, 2, 3, 1]
2233 *
2234 * // Only removes adjacent duplicates, not all duplicates
2235 * const mixed = Chunk.make("a", "a", "b", "a", "a")
2236 * Chunk.toArray(Chunk.dedupeAdjacent(mixed)) // => ["a", "b", "a"]
2237 * ```
2238 *
2239 * @category filtering
2240 * @since 2.0.0
2241 */
2242export const dedupeAdjacent = <A>(self: Chunk<A>): Chunk<A> => fromArrayUnsafe(RA.dedupeAdjacent(self))
2243
2244/**
2245 * Takes a `Chunk` of pairs and returns two corresponding `Chunk`s.
2246 *
2247 * **Details**
2248 *
2249 * This function is the reverse of `zip`.
2250 *
2251 * **Example** (Unzipping pairs)
2252 *
2253 * ```ts import.meta.vitest
2254 * import { Chunk } from "effect"
2255 *
2256 * const pairs = Chunk.make(
2257 * [1, "a"] as const,
2258 * [2, "b"] as const,
2259 * [3, "c"] as const
2260 * )
2261 * const [numbers, letters] = Chunk.unzip(pairs)
2262 * Chunk.toArray(numbers) // => [1, 2, 3]
2263 * Chunk.toArray(letters) // => ["a", "b", "c"]
2264 *
2265 * // Empty chunk
2266 * const empty = Chunk.empty<[number, string]>()
2267 * const [emptyNums, emptyStrs] = Chunk.unzip(empty)
2268 * Chunk.toArray(emptyNums) // => []
2269 * Chunk.toArray(emptyStrs) // => []
2270 * ```
2271 *
2272 * @category splitting
2273 * @since 2.0.0
2274 */
2275export const unzip = <A, B>(self: Chunk<readonly [A, B]>): [Chunk<A>, Chunk<B>] => {
2276 const [left, right] = RA.unzip(toReadonlyArray(self))
2277 return [fromArrayUnsafe(left), fromArrayUnsafe(right)]
2278}
2279
2280/**
2281 * Zips this chunk pointwise with the specified chunk using the specified combiner.
2282 *
2283 * **Example** (Zipping chunks with a function)
2284 *
2285 * ```ts import.meta.vitest
2286 * import { Chunk } from "effect"
2287 *
2288 * const numbers = Chunk.make(1, 2, 3)
2289 * const letters = Chunk.make("a", "b", "c")
2290 * Chunk.toArray(Chunk.zipWith(numbers, letters, (n, l) => `${n}-${l}`)) // => ["1-a", "2-b", "3-c"]
2291 *
2292 * // Different lengths - takes minimum
2293 * const short = Chunk.make(1, 2)
2294 * const long = Chunk.make("a", "b", "c", "d")
2295 * Chunk.toArray(Chunk.zipWith(short, long, (n, l) => [n, l])) // => [[1, "a"], [2, "b"]]
2296 * ```
2297 *
2298 * @category zipping
2299 * @since 2.0.0
2300 */
2301export const zipWith: {
2302 <A, B, C>(that: Chunk<B>, f: (a: A, b: B) => C): (self: Chunk<A>) => Chunk<C>
2303 <A, B, C>(self: Chunk<A>, that: Chunk<B>, f: (a: A, b: B) => C): Chunk<C>
2304} = dual(
2305 3,
2306 <A, B, C>(self: Chunk<A>, that: Chunk<B>, f: (a: A, b: B) => C): Chunk<C> =>
2307 fromArrayUnsafe(RA.zipWith(toReadonlyArray(self), toReadonlyArray(that), f))
2308)
2309
2310/**
2311 * Zips this chunk pointwise with the specified chunk.
2312 *
2313 * **Example** (Zipping chunks)
2314 *
2315 * ```ts import.meta.vitest
2316 * import { Chunk } from "effect"
2317 *
2318 * const numbers = Chunk.make(1, 2, 3)
2319 * const letters = Chunk.make("a", "b", "c")
2320 * Chunk.toArray(Chunk.zip(numbers, letters)) // => [[1, "a"], [2, "b"], [3, "c"]]
2321 *
2322 * // Different lengths - takes minimum length
2323 * const short = Chunk.make(1, 2)
2324 * const long = Chunk.make("a", "b", "c", "d")
2325 * Chunk.toArray(Chunk.zip(short, long)) // => [[1, "a"], [2, "b"]]
2326 * ```
2327 *
2328 * @category zipping
2329 * @since 2.0.0
2330 */
2331export const zip: {
2332 <B>(that: Chunk<B>): <A>(self: Chunk<A>) => Chunk<[A, B]>
2333 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<[A, B]>
2334} = dual(
2335 2,
2336 <A, B>(self: Chunk<A>, that: Chunk<B>): Chunk<[A, B]> => zipWith(self, that, (a, b) => [a, b])
2337)
2338
2339/**
2340 * Deletes the element at the specified index, creating a new `Chunk`.
2341 *
2342 * **Example** (Removing an element)
2343 *
2344 * ```ts import.meta.vitest
2345 * import { Chunk } from "effect"
2346 *
2347 * const chunk = Chunk.make("a", "b", "c", "d")
2348 * Chunk.toArray(Chunk.remove(chunk, 1)) // => ["a", "c", "d"]
2349 *
2350 * // Remove first element
2351 * Chunk.toArray(Chunk.remove(chunk, 0)) // => ["b", "c", "d"]
2352 *
2353 * // Index out of bounds returns same chunk
2354 * Chunk.toArray(Chunk.remove(chunk, 10)) // => ["a", "b", "c", "d"]
2355 * ```
2356 *
2357 * @category transforming
2358 * @since 2.0.0
2359 */
2360export const remove: {
2361 (i: number): <A>(self: Chunk<A>) => Chunk<A>
2362 <A>(self: Chunk<A>, i: number): Chunk<A>
2363} = dual(
2364 2,
2365 <A>(self: Chunk<A>, i: number): Chunk<A> => fromArrayUnsafe(RA.remove(toReadonlyArray(self), i))
2366)
2367
2368/**
2369 * Applies a function to the element at the specified index safely, creating a new `Chunk`,
2370 * or returns `None` if the index is out of bounds.
2371 *
2372 * **Example** (Modifying an element)
2373 *
2374 * ```ts import.meta.vitest
2375 * import { Chunk, Option } from "effect"
2376 *
2377 * const chunk = Chunk.make(1, 2, 3, 4)
2378 * Chunk.modify(chunk, 1, (n) => n * 10) // => Option.some(Chunk.make(1, 20, 3, 4))
2379 *
2380 * // Index out of bounds returns None
2381 * chunk.pipe(Chunk.modify(10, (n) => n * 10)) // => Option.none()
2382 *
2383 * // Negative index returns None
2384 * chunk.pipe(Chunk.modify(-1, (n) => n * 10)) // => Option.none()
2385 * ```
2386 *
2387 * @category transforming
2388 * @since 2.0.0
2389 */
2390export const modify: {
2391 <A, B>(i: number, f: (a: A) => B): (self: Chunk<A>) => O.Option<Chunk<A | B>>
2392 <A, B>(self: Chunk<A>, i: number, f: (a: A) => B): O.Option<Chunk<A | B>>
2393} = dual(
2394 3,
2395 <A, B>(self: Chunk<A>, i: number, f: (a: A) => B): O.Option<Chunk<A | B>> =>
2396 pipe(RA.modify(toReadonlyArray(self), i, f), O.map(fromArrayUnsafe))
2397)
2398
2399/**
2400 * Changes the element at the specified index safely, creating a new `Chunk`,
2401 * or returns `None` if the index is out of bounds.
2402 *
2403 * **Example** (Replacing an element)
2404 *
2405 * ```ts import.meta.vitest
2406 * import { Chunk, Option } from "effect"
2407 *
2408 * const chunk = Chunk.make("a", "b", "c", "d")
2409 * Chunk.replace(chunk, 1, "X") // => Option.some(Chunk.make("a", "X", "c", "d"))
2410 *
2411 * // Index out of bounds returns None
2412 * chunk.pipe(Chunk.replace(10, "Y")) // => Option.none()
2413 *
2414 * // Negative index returns None
2415 * chunk.pipe(Chunk.replace(-1, "Z")) // => Option.none()
2416 * ```
2417 *
2418 * @category transforming
2419 * @since 2.0.0
2420 */
2421export const replace: {
2422 <B>(i: number, b: B): <A>(self: Chunk<A>) => O.Option<Chunk<B | A>>
2423 <A, B>(self: Chunk<A>, i: number, b: B): O.Option<Chunk<B | A>>
2424} = dual(3, <A, B>(self: Chunk<A>, i: number, b: B): O.Option<Chunk<B | A>> => modify(self, i, () => b))
2425
2426/**
2427 * Returns a non-empty `Chunk` of length `n` with element `i` initialized by `f(i)`.
2428 *
2429 * **Details**
2430 *
2431 * `n` is rounded down and normalized to an integer greater than or equal to
2432 * `1`. `NaN` is treated as `1`.
2433 *
2434 * **Example** (Generating chunks from indices)
2435 *
2436 * ```ts import.meta.vitest
2437 * import { Chunk } from "effect"
2438 *
2439 * Chunk.toArray(Chunk.makeBy(5, (i) => i * 2)) // => [0, 2, 4, 6, 8]
2440 * ```
2441 *
2442 * @category constructors
2443 * @since 2.0.0
2444 */
2445export const makeBy: {
2446 <A>(f: (i: number) => A): (n: number) => NonEmptyChunk<A>
2447 <A>(n: number, f: (i: number) => A): NonEmptyChunk<A>
2448} = dual(2, (n, f) => fromIterable(RA.makeBy(n, f)))
2449
2450/**
2451 * Creates a non-empty `Chunk` of consecutive integers from `start` through
2452 * `end`, inclusive.
2453 *
2454 * **Details**
2455 *
2456 * If `start` is greater than `end`, returns a single-element chunk containing
2457 * `start`.
2458 *
2459 * **Example** (Creating a range)
2460 *
2461 * ```ts import.meta.vitest
2462 * import { Chunk } from "effect"
2463 *
2464 * Chunk.toArray(Chunk.range(1, 5)) // => [1, 2, 3, 4, 5]
2465 * ```
2466 *
2467 * @category constructors
2468 * @since 2.0.0
2469 */
2470export const range = (start: number, end: number): NonEmptyChunk<number> =>
2471 start <= end ? makeBy(end - start + 1, (i) => start + i) : of(start)
2472
2473// -------------------------------------------------------------------------------------
2474// re-exports from ReadonlyArray
2475// -------------------------------------------------------------------------------------
2476
2477/**
2478 * Returns a function that checks if a `Chunk` contains a given value using the default `Equivalence`.
2479 *
2480 * **Example** (Checking membership)
2481 *
2482 * ```ts import.meta.vitest
2483 * import { Chunk } from "effect"
2484 *
2485 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2486 * Chunk.contains(chunk, 3) // => true
2487 * Chunk.contains(chunk, 6) // => false
2488 *
2489 * // Works with strings
2490 * const words = Chunk.make("apple", "banana", "cherry")
2491 * Chunk.contains(words, "banana") // => true
2492 * Chunk.contains(words, "grape") // => false
2493 *
2494 * // Empty chunk
2495 * Chunk.contains(Chunk.empty<number>(), 1) // => false
2496 * ```
2497 *
2498 * @category predicates
2499 * @since 2.0.0
2500 */
2501export const contains: {
2502 <A>(a: A): (self: Chunk<A>) => boolean
2503 <A>(self: Chunk<A>, a: A): boolean
2504} = RA.contains
2505
2506/**
2507 * Returns a function that checks if a `Chunk` contains a given value using a provided `isEquivalent` function.
2508 *
2509 * **Example** (Checking membership with custom equivalence)
2510 *
2511 * ```ts import.meta.vitest
2512 * import { Chunk } from "effect"
2513 *
2514 * const chunk = Chunk.make({ id: 1, name: "Alice" }, { id: 2, name: "Bob" })
2515 *
2516 * // Custom equivalence by id
2517 * const containsById = Chunk.containsWith<{ id: number; name: string }>((a, b) =>
2518 * a.id === b.id
2519 * )
2520 * containsById(chunk, { id: 1, name: "Different" }) // => true
2521 * containsById(chunk, { id: 3, name: "Charlie" }) // => false
2522 *
2523 * // Case-insensitive string comparison
2524 * const words = Chunk.make("Apple", "Banana", "Cherry")
2525 * const containsCaseInsensitive = Chunk.containsWith<string>((a, b) =>
2526 * a.toLowerCase() === b.toLowerCase()
2527 * )
2528 * containsCaseInsensitive(words, "apple") // => true
2529 * containsCaseInsensitive(words, "grape") // => false
2530 * ```
2531 *
2532 * @category predicates
2533 * @since 2.0.0
2534 */
2535export const containsWith: <A>(
2536 isEquivalent: (self: A, that: A) => boolean
2537) => {
2538 (a: A): (self: Chunk<A>) => boolean
2539 (self: Chunk<A>, a: A): boolean
2540} = RA.containsWith
2541
2542/**
2543 * Returns the first element that satisfies the specified
2544 * predicate, or `None` if no such element exists.
2545 *
2546 * **Example** (Finding the first matching element)
2547 *
2548 * ```ts import.meta.vitest
2549 * import { Chunk, Option } from "effect"
2550 *
2551 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2552 * Chunk.findFirst(chunk, (n) => n > 3) // => Option.some(4)
2553 *
2554 * // No match found
2555 * Chunk.findFirst(chunk, (n) => n > 10) // => Option.none()
2556 *
2557 * // With type refinement
2558 * const mixed = Chunk.make(1, "hello", 2, "world", 3)
2559 * const firstString = Chunk.findFirst(
2560 * mixed,
2561 * (x): x is string => typeof x === "string"
2562 * )
2563 * firstString // => Option.some("hello")
2564 * ```
2565 *
2566 * @category searching
2567 * @since 2.0.0
2568 */
2569export const findFirst: {
2570 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Chunk<A>) => Option<B>
2571 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => Option<A>
2572 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): Option<B>
2573 <A>(self: Chunk<A>, predicate: Predicate<A>): Option<A>
2574} = RA.findFirst
2575
2576/**
2577 * Returns the first index for which a predicate holds.
2578 *
2579 * **Example** (Finding the first matching index)
2580 *
2581 * ```ts import.meta.vitest
2582 * import { Chunk, Option } from "effect"
2583 *
2584 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2585 * Chunk.findFirstIndex(chunk, (n) => n > 3) // => Option.some(3)
2586 *
2587 * // No match found
2588 * Chunk.findFirstIndex(chunk, (n) => n > 10) // => Option.none()
2589 *
2590 * // Find first even number
2591 * Chunk.findFirstIndex(chunk, (n) => n % 2 === 0) // => Option.some(1)
2592 * ```
2593 *
2594 * @category searching
2595 * @since 2.0.0
2596 */
2597export const findFirstIndex: {
2598 <A>(predicate: Predicate<A>): (self: Chunk<A>) => O.Option<number>
2599 <A>(self: Chunk<A>, predicate: Predicate<A>): O.Option<number>
2600} = dual(
2601 2,
2602 <A>(self: Chunk<A>, predicate: Predicate<A>): O.Option<number> => RA.findFirstIndex(self, predicate)
2603)
2604
2605/**
2606 * Finds the last element for which a predicate holds.
2607 *
2608 * **Example** (Finding the last matching element)
2609 *
2610 * ```ts import.meta.vitest
2611 * import { Chunk, Option } from "effect"
2612 *
2613 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2614 * Chunk.findLast(chunk, (n) => n < 4) // => Option.some(3)
2615 *
2616 * // No match found
2617 * Chunk.findLast(chunk, (n) => n > 10) // => Option.none()
2618 *
2619 * // Find last even number
2620 * Chunk.findLast(chunk, (n) => n % 2 === 0) // => Option.some(4)
2621 * ```
2622 *
2623 * @category searching
2624 * @since 2.0.0
2625 */
2626export const findLast: {
2627 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Chunk<A>) => Option<B>
2628 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => Option<A>
2629 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): Option<B>
2630 <A>(self: Chunk<A>, predicate: Predicate<A>): Option<A>
2631} = dual(2, <A>(self: Chunk<A>, predicate: Predicate<A>): Option<A> => RA.findLast(toReadonlyArray(self), predicate))
2632
2633/**
2634 * Returns the last index for which a predicate holds.
2635 *
2636 * **Example** (Finding the last matching index)
2637 *
2638 * ```ts import.meta.vitest
2639 * import { Chunk, Option } from "effect"
2640 *
2641 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2642 * Chunk.findLastIndex(chunk, (n) => n < 4) // => Option.some(2)
2643 *
2644 * // No match found
2645 * Chunk.findLastIndex(chunk, (n) => n > 10) // => Option.none()
2646 *
2647 * // Find last even number index
2648 * Chunk.findLastIndex(chunk, (n) => n % 2 === 0) // => Option.some(3)
2649 * ```
2650 *
2651 * @category searching
2652 * @since 2.0.0
2653 */
2654export const findLastIndex: {
2655 <A>(predicate: Predicate<A>): (self: Chunk<A>) => O.Option<number>
2656 <A>(self: Chunk<A>, predicate: Predicate<A>): O.Option<number>
2657} = dual(
2658 2,
2659 <A>(self: Chunk<A>, predicate: Predicate<A>): O.Option<number> => RA.findLastIndex(toReadonlyArray(self), predicate)
2660)
2661
2662/**
2663 * Checks whether a predicate holds true for every `Chunk` element.
2664 *
2665 * **Example** (Checking every element)
2666 *
2667 * ```ts import.meta.vitest
2668 * import { Chunk } from "effect"
2669 *
2670 * const allPositive = Chunk.make(1, 2, 3, 4, 5)
2671 * Chunk.every(allPositive, (n) => n > 0) // => true
2672 * Chunk.every(allPositive, (n) => n > 3) // => false
2673 *
2674 * // Empty chunk returns true
2675 * Chunk.every(Chunk.empty<number>(), (n) => n > 0) // => true
2676 *
2677 * // Type refinement
2678 * const mixed = Chunk.make(1, 2, 3)
2679 * if (Chunk.every(mixed, (x): x is number => typeof x === "number")) {
2680 * // mixed is now typed as Chunk<number>
2681 * }
2682 * ```
2683 *
2684 * @category guards
2685 * @since 2.0.0
2686 */
2687export const every: {
2688 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Chunk<A>) => self is Chunk<B>
2689 <A>(predicate: Predicate<A>): (self: Chunk<A>) => boolean
2690 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): self is Chunk<B>
2691 <A>(self: Chunk<A>, predicate: Predicate<A>): boolean
2692} = dual(
2693 2,
2694 <A, B extends A>(self: Chunk<A>, refinement: Refinement<A, B>): self is Chunk<B> => {
2695 const as = toReadonlyArray(self)
2696 for (let i = 0; i < as.length; i++) {
2697 if (!refinement(as[i])) {
2698 return false
2699 }
2700 }
2701 return true
2702 }
2703)
2704
2705/**
2706 * Checks whether a predicate holds true for some `Chunk` element.
2707 *
2708 * **Example** (Checking for some matching element)
2709 *
2710 * ```ts import.meta.vitest
2711 * import { Chunk } from "effect"
2712 *
2713 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2714 * Chunk.some(chunk, (n) => n > 4) // => true
2715 * Chunk.some(chunk, (n) => n > 10) // => false
2716 *
2717 * // Empty chunk returns false
2718 * Chunk.some(Chunk.empty<number>(), (n) => n > 0) // => false
2719 *
2720 * // Check for specific value
2721 * const words = Chunk.make("apple", "banana", "cherry")
2722 * Chunk.some(words, (word) => word.includes("ban")) // => true
2723 * ```
2724 *
2725 * @category guards
2726 * @since 2.0.0
2727 */
2728export const some: {
2729 <A>(predicate: Predicate<NoInfer<A>>): (self: Chunk<A>) => self is NonEmptyChunk<A>
2730 <A>(self: Chunk<A>, predicate: Predicate<A>): self is NonEmptyChunk<A>
2731} = dual(
2732 2,
2733 <A>(self: Chunk<A>, predicate: Predicate<A>): self is NonEmptyChunk<A> => {
2734 const as = toReadonlyArray(self)
2735 for (let i = 0; i < as.length; i++) {
2736 if (predicate(as[i])) {
2737 return true
2738 }
2739 }
2740 return false
2741 }
2742)
2743
2744/**
2745 * Joins the elements together with "sep" in the middle.
2746 *
2747 * **Example** (Joining chunks into a string)
2748 *
2749 * ```ts import.meta.vitest
2750 * import { Chunk } from "effect"
2751 *
2752 * const chunk = Chunk.make("apple", "banana", "cherry")
2753 * Chunk.join(chunk, ", ") // => "apple, banana, cherry"
2754 *
2755 * // With different separator
2756 * Chunk.join(chunk, " | ") // => "apple | banana | cherry"
2757 *
2758 * // Empty chunk
2759 * Chunk.join(Chunk.empty<string>(), ", ") // => ""
2760 *
2761 * // Single element
2762 * Chunk.join(Chunk.make("hello"), ", ") // => "hello"
2763 * ```
2764 *
2765 * @category folding
2766 * @since 2.0.0
2767 */
2768export const join: {
2769 (sep: string): (self: Chunk<string>) => string
2770 (self: Chunk<string>, sep: string): string
2771} = dual(2, (self: Chunk<string>, sep: string): string => toReadonlyArray(self).join(sep))
2772
2773/**
2774 * Reduces the elements of a chunk from left to right.
2775 *
2776 * **Example** (Reducing from the left)
2777 *
2778 * ```ts import.meta.vitest
2779 * import { Chunk } from "effect"
2780 *
2781 * const chunk = Chunk.make(1, 2, 3, 4, 5)
2782 * Chunk.reduce(chunk, 0, (acc, n) => acc + n) // => 15
2783 *
2784 * // String concatenation with index
2785 * const words = Chunk.make("a", "b", "c")
2786 * Chunk.reduce(words, "", (acc, word, i) => acc + `${i}:${word} `).trimEnd() // => "0:a 1:b 2:c"
2787 *
2788 * // Find maximum
2789 * Chunk.reduce(chunk, -Infinity, (acc, n) => Math.max(acc, n)) // => 5
2790 * ```
2791 *
2792 * @category folding
2793 * @since 2.0.0
2794 */
2795export const reduce: {
2796 <B, A>(b: B, f: (b: B, a: A, i: number) => B): (self: Chunk<A>) => B
2797 <A, B>(self: Chunk<A>, b: B, f: (b: B, a: A, i: number) => B): B
2798} = RA.reduce
2799
2800/**
2801 * Reduces the elements of a chunk from right to left.
2802 *
2803 * **Example** (Reducing from the right)
2804 *
2805 * ```ts import.meta.vitest
2806 * import { Chunk } from "effect"
2807 *
2808 * const chunk = Chunk.make(1, 2, 3, 4)
2809 * Chunk.reduceRight(chunk, 0, (acc, n) => acc + n) // => 10
2810 *
2811 * // String building (right to left)
2812 * const words = Chunk.make("a", "b", "c")
2813 * Chunk.reduceRight(
2814 * words,
2815 * "",
2816 * (acc, word, i) => acc + `${i}:${word} `
2817 * ).trim() // => "2:c 1:b 0:a"
2818 *
2819 * // Subtract from right to left
2820 * Chunk.reduceRight(chunk, 0, (acc, n) => n - acc) // => -2
2821 * ```
2822 *
2823 * @category folding
2824 * @since 2.0.0
2825 */
2826export const reduceRight: {
2827 <B, A>(b: B, f: (b: B, a: A, i: number) => B): (self: Chunk<A>) => B
2828 <A, B>(self: Chunk<A>, b: B, f: (b: B, a: A, i: number) => B): B
2829} = RA.reduceRight
2830
2831/**
2832 * Creates a `Chunk` of values not included in the other given `Chunk` using the provided `isEquivalent` function.
2833 * The order and references of result values are determined by the first `Chunk`.
2834 *
2835 * **Example** (Computing difference with custom equivalence)
2836 *
2837 * ```ts import.meta.vitest
2838 * import { Chunk } from "effect"
2839 *
2840 * const chunk1 = Chunk.make({ id: 1, name: "Alice" }, { id: 2, name: "Bob" })
2841 * const chunk2 = Chunk.make({ id: 1, name: "Alice" }, { id: 3, name: "Charlie" })
2842 *
2843 * // Custom equivalence by id
2844 * const byId = Chunk.differenceWith<{ id: number; name: string }>((a, b) =>
2845 * a.id === b.id
2846 * )
2847 * Chunk.toArray(byId(chunk1, chunk2)) // => [{ id: 2, name: "Bob" }]
2848 *
2849 * // String comparison case-insensitive
2850 * const words1 = Chunk.make("Apple", "Banana", "Cherry")
2851 * const words2 = Chunk.make("apple", "grape")
2852 * const caseInsensitive = Chunk.differenceWith<string>((a, b) =>
2853 * a.toLowerCase() === b.toLowerCase()
2854 * )
2855 * Chunk.toArray(caseInsensitive(words1, words2)) // => ["Banana", "Cherry"]
2856 * ```
2857 *
2858 * @category filtering
2859 * @since 3.2.0
2860 */
2861export const differenceWith = <A>(isEquivalent: (self: A, that: A) => boolean): {
2862 (that: Chunk<A>): (self: Chunk<A>) => Chunk<A>
2863 (self: Chunk<A>, that: Chunk<A>): Chunk<A>
2864} => {
2865 return dual(
2866 2,
2867 (self: Chunk<A>, that: Chunk<A>): Chunk<A> => fromArrayUnsafe(RA.differenceWith(isEquivalent)(self, that))
2868 )
2869}
2870
2871/**
2872 * Creates a `Chunk` of values not included in the other given `Chunk`.
2873 * The order and references of result values are determined by the first `Chunk`.
2874 *
2875 * **Example** (Computing chunk difference)
2876 *
2877 * ```ts import.meta.vitest
2878 * import { Chunk } from "effect"
2879 *
2880 * const chunk1 = Chunk.make(1, 2, 3, 4, 5)
2881 * const chunk2 = Chunk.make(3, 4, 6, 7)
2882 * Chunk.toArray(Chunk.difference(chunk1, chunk2)) // => [1, 2, 5]
2883 *
2884 * // String difference
2885 * const words1 = Chunk.make("apple", "banana", "cherry")
2886 * const words2 = Chunk.make("banana", "grape")
2887 * Chunk.toArray(Chunk.difference(words1, words2)) // => ["apple", "cherry"]
2888 *
2889 * // Empty second chunk returns original
2890 * Chunk.toArray(Chunk.difference(chunk1, Chunk.empty<number>())) // => [1, 2, 3, 4, 5]
2891 * ```
2892 *
2893 * @category filtering
2894 * @since 3.2.0
2895 */
2896export const difference: {
2897 <A>(that: Chunk<A>): (self: Chunk<A>) => Chunk<A>
2898 <A>(self: Chunk<A>, that: Chunk<A>): Chunk<A>
2899} = dual(
2900 2,
2901 <A>(self: Chunk<A>, that: Chunk<A>): Chunk<A> => fromArrayUnsafe(RA.difference(self, toReadonlyArray(that)))
2902)