# Iterable

The `Iterable` module operates on **any** value that implements `[Symbol.iterator]` —
arrays, strings, `Set`s, `Map`s, generators, and your own custom lazy sequences.
Unlike `Array`, its transformations are **lazy**: `map`, `filter`, `take`, `drop`,
and friends return new iterables that do no work until something pulls values out of
them. This lets you describe pipelines over unbounded sequences and only pay for the
slice you actually materialize.

```ts
import { Array, Iterable } from "effect"

// An infinite sequence of naturals — nothing runs yet.
const naturals = Iterable.range(1)

// Compose lazily: still nothing runs.
const evenSquares = Iterable.filter(
  Iterable.map(naturals, (n) => n * n),
  (n) => n % 2 === 0
)

// Bound it, then materialize. Only 4 squares are ever computed.
const firstFour = Iterable.take(evenSquares, 4)
console.log(Array.fromIterable(firstFour))
// => [4, 16, 36, 64]
```

## Mental model: producers, transformers, consumers

The whole module falls into three buckets, and knowing which is which tells you when
work happens:

- **Producers** create iterables, possibly infinite: `range`, `makeBy`, `repeat`,
  `forever`, `unfold`, `replicate`, `of`, `empty`.
- **Transformers** take an iterable and return a new lazy iterable: `map`, `filter`,
  `flatMap`, `take`, `drop`, `scan`, `zip`, `intersperse`, `chunksOf`, `group`, … No
  work happens until the result is iterated.
- **Consumers** pull values and produce a final answer, doing the work immediately:
  `reduce`, `size`, `head`, `findFirst`, `some`, `countBy`, `forEach`, `contains`,
  `groupBy`, and `Array.fromIterable` / `Array.from`.

```ts
import { Array, Iterable } from "effect"

// `map` is a transformer: this logs nothing.
const mapped = Iterable.map([1, 2, 3], (n) => {
  console.log("mapping", n)
  return n * 10
})

// `Array.fromIterable` is a consumer: now the logs fire and we get a result.
console.log(Array.fromIterable(mapped))
// => mapping 1
// => mapping 2
// => mapping 3
// => [10, 20, 30]
```

:::caution[Iterators are single-use]
Many JavaScript iterables (notably generators) yield an iterator that is exhausted
after one pass. Consuming such a value twice (for example calling `size` and then
`Array.fromIterable`) may produce nothing the second time. Arrays, strings, `Set`s,
and `Map`s are re-iterable; bare generators are not.
:::

## `Iterable` vs `Array`: when to reach for which

Both modules share most of the same operation names, but they make opposite tradeoffs:

| | `Iterable` | `Array` |
| --- | --- | --- |
| Evaluation | Lazy — intermediate steps don't allocate | Eager — each step allocates a new array |
| Indexing / length | No random access; `size` walks the whole thing | O(1) `length`, index access, slicing |
| Infinite sequences | Supported (`range`, `forever`, `unfold`) | Not possible |
| Best for | Streaming, fused pipelines, "first N matching" | Random access, repeated reads, small finite data |

Reach for `Iterable` when you are chaining several transformations, when the source may
be unbounded, or when you only need a prefix of a large computation. Reach for `Array`
when you need indexing, length, or a concrete materialized collection. Convert from one
to the other with `Array.fromIterable`.

```ts
import { Array, Iterable } from "effect"

// Lazy: only enough candidates are tested to find the first 3 primes above 100.
const isPrime = (n: number) =>
  n > 1 &&
  !Iterable.some(Iterable.range(2, Math.floor(Math.sqrt(n))), (d) => n % d === 0)

const bigPrimes = Iterable.filter(Iterable.range(101), isPrime)
console.log(Array.fromIterable(Iterable.take(bigPrimes, 3)))
// => [101, 103, 107]
```

## `NonEmptyIterable`: a compile-time non-empty guarantee

`NonEmptyIterable<A>` is an `Iterable<A>` branded with a type-level proof that it
contains at least one element. It is accepted anywhere an `Iterable<A>` is, but lets
callers safely read the head without an `Option`. Use it for APIs (reductions,
aggregations, comparisons) that are undefined for empty input.

```ts
import { NonEmptyIterable } from "effect"

function firstOf<A>(data: NonEmptyIterable.NonEmptyIterable<A>): A {
  // `unprepend` is safe here because the type guarantees an element exists.
  const [first] = NonEmptyIterable.unprepend(data)
  return first
}

// A generator typed as NonEmptyIterable satisfies the brand without a cast.
function* oneToThree(): NonEmptyIterable.NonEmptyIterable<number> {
  yield 1
  yield 2
  yield 3
}

console.log(firstOf(oneToThree()))
// => 1
```

:::caution[The brand is a static promise, not a runtime check]
`NonEmptyIterable<A>` carries a type-level brand (`[nonEmpty]`) that ordinary
iterables — including `Array`s and the `NonEmptyArray` returned by `Array.make` — do
**not** structurally have. So a value typically becomes a `NonEmptyIterable` either by
being produced from a function typed to return one, or by an explicit
`as unknown as NonEmptyIterable.NonEmptyIterable<...>` assertion. Only assert
non-emptiness after a real check or a constructor that proves it — casting an empty
value will pass type-checking but `unprepend` will throw at runtime.
:::

---

## Reference

Every example materializes lazy results with `Array.fromIterable` so the `// =>`
comments show concrete values. Functions are grouped by role; remember the
producer / transformer / consumer distinction from above.

### Constructors and infinite sequences

#### `makeBy`

Builds an iterable by applying a function to consecutive indices starting at `0`. Omit
`length` for an infinite sequence.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.makeBy((n) => n * 2, { length: 4 })))
// => [0, 2, 4, 6]
```

#### `range`

Integers from `start`, increasing by 1. With `end` (inclusive) it is finite; without
`end` it is infinite.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.range(1, 4)))
// => [1, 2, 3, 4]
console.log(Array.fromIterable(Iterable.take(Iterable.range(1), 3)))
// => [1, 2, 3]
```

#### `replicate`

Repeats a single value `n` times (`n` is clamped to at least 1).

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.replicate("a", 3)))
// => ["a", "a", "a"]
```

#### `repeat`

Repeats the entire contents of an iterable `n` times. Lazy — a fresh iterator is taken
from the source for each pass, so the source must be re-iterable.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.repeat([1, 2], 3)))
// => [1, 2, 1, 2, 1, 2]
```

#### `forever`

Repeats an iterable without bound. Always pair it with a terminating consumer such as
`take`.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.take(Iterable.forever([1, 2]), 5)))
// => [1, 2, 1, 2, 1]
```

#### `fromRecord`

Turns a record into an iterable of `[key, value]` entry tuples.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.fromRecord({ a: 1, b: 2 })))
// => [["a", 1], ["b", 2]]
```

#### `empty`

An iterable that yields nothing. Useful as a base case or as the "skip" result of a
`flatMap`.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.empty<number>()))
// => []
```

#### `of`

Wraps a single value in an iterable.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.of(42)))
// => [42]
```

#### `unfold`

Generates values from a seed: `f` returns `Option.some([value, nextSeed])` to continue
or `Option.none()` to stop. The dual of `reduce`.

```ts
import { Array, Iterable, Option } from "effect"

const countdown = Iterable.unfold(3, (n) =>
  n > 0 ? Option.some([n, n - 1] as const) : Option.none()
)
console.log(Array.fromIterable(countdown))
// => [3, 2, 1]
```

### Concatenation

#### `prepend`

Yields one element before the existing elements.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.prepend([2, 3], 1)))
// => [1, 2, 3]
```

#### `prependAll`

Yields all elements of another iterable before `self`.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.prependAll([1, 2], ["a", "b"])))
// => ["a", "b", 1, 2]
```

#### `append`

Yields `self`, then one trailing element. If `self` never completes, the element is
never reached.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.append([1, 2, 3], 4)))
// => [1, 2, 3, 4]
```

#### `appendAll`

Concatenates two iterables lazily; `that` is not touched until `self` is exhausted.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.appendAll([1, 2], [3, 4])))
// => [1, 2, 3, 4]
```

### Slicing

#### `take`

Keeps at most the first `n` elements. The canonical way to bound an infinite iterable.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.take(Iterable.range(1), 3)))
// => [1, 2, 3]
```

#### `takeWhile`

Keeps the longest leading run for which the predicate holds, then stops. Supports type
refinements.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.takeWhile([2, 4, 6, 3, 8], (n) => n % 2 === 0)))
// => [2, 4, 6]
```

#### `drop`

Skips the first `n` elements and yields the rest. Combine with `take` to slice.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.take(Iterable.drop([1, 2, 3, 4, 5], 1), 3)))
// => [2, 3, 4]
```

#### `chunksOf`

Splits into arrays of length `n`; the final chunk may be shorter.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.chunksOf([1, 2, 3, 4, 5], 2)))
// => [[1, 2], [3, 4], [5]]
```

### Accessing and size (consumers)

#### `isEmpty`

Checks whether the iterable yields no elements by pulling a single value. Acts as a type
guard narrowing to `Iterable<never>`.

```ts
import { Iterable } from "effect"

console.log(Iterable.isEmpty([]))
// => true
console.log(Iterable.isEmpty([1]))
// => false
```

#### `size`

Counts elements by walking the entire iterable. Never call on an unbounded source.

```ts
import { Iterable } from "effect"

console.log(Iterable.size([1, 2, 3, 4, 5]))
// => 5
```

#### `head`

Returns the first element as an `Option`, `None` if empty.

```ts
import { Iterable } from "effect"

console.log(Iterable.head([1, 2, 3]))
// => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(Iterable.head([]))
// => { _id: 'Option', _tag: 'None' }
```

#### `headUnsafe`

Returns the first element directly, throwing on an empty iterable. Use only when you
know the iterable is non-empty.

```ts
import { Iterable } from "effect"

console.log(Iterable.headUnsafe([1, 2, 3]))
// => 1
// Iterable.headUnsafe([]) // throws Error: "headUnsafe: empty iterable"
```

### Searching (consumers)

#### `findFirst`

Returns the first matching element as an `Option`. Accepts a boolean predicate, a type
refinement, or an `Option`-returning function (which also transforms the result).

```ts
import { Iterable } from "effect"

console.log(Iterable.findFirst([1, 3, 4, 6], (n) => n % 2 === 0))
// => { _id: 'Option', _tag: 'Some', value: 4 }
```

#### `findLast`

Like `findFirst` but returns the last match. Always walks the whole iterable.

```ts
import { Iterable } from "effect"

console.log(Iterable.findLast([1, 4, 6, 8, 2], (n) => n % 2 === 0))
// => { _id: 'Option', _tag: 'Some', value: 2 }
```

#### `contains`

Tests membership using Effect's default `Equal` equivalence (so it works with
value-equal data types, not just primitives).

```ts
import { Iterable } from "effect"

console.log(Iterable.contains([1, 2, 3], 2))
// => true
console.log(Iterable.contains([1, 2, 3], 9))
// => false
```

#### `containsWith`

Builds a `contains` that uses a custom equivalence function.

```ts
import { Iterable } from "effect"

const containsCi = Iterable.containsWith<string>(
  (a, b) => a.toLowerCase() === b.toLowerCase()
)
console.log(containsCi(["Hello", "World"], "hello"))
// => true
```

### Mapping and folding

#### `map`

Transforms each element. The callback receives the index. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.map([1, 2, 3], (n) => n * n)))
// => [1, 4, 9]
```

#### `flatMap`

Maps each element to an iterable, then concatenates the results. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.flatMap([1, 2, 3], (n) => Iterable.range(1, n))))
// => [1, 1, 2, 1, 2, 3]
```

#### `flatten`

Concatenates an iterable of iterables, one level deep. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.flatten([[1, 2], [3, 4], [5]])))
// => [1, 2, 3, 4, 5]
```

#### `filterMap`

Maps and filters in one pass using a `Result`: `Result.succeed(b)` keeps `b`,
`Result.failVoid` drops the element. Lazy.

```ts
import { Array, Iterable, Result } from "effect"

const parsed = Iterable.filterMap(["1", "x", "3"], (s) => {
  const n = Number(s)
  return Number.isNaN(n) ? Result.failVoid : Result.succeed(n)
})
console.log(Array.fromIterable(parsed))
// => [1, 3]
```

#### `filterMapWhile`

Like `filterMap`, but stops at the first `Result.failVoid` instead of skipping it.

```ts
import { Array, Iterable, Result } from "effect"

const upToInvalid = Iterable.filterMapWhile(["1", "2", "x", "4"], (s) => {
  const n = Number(s)
  return Number.isNaN(n) ? Result.failVoid : Result.succeed(n)
})
console.log(Array.fromIterable(upToInvalid))
// => [1, 2]
```

#### `filter`

Keeps elements matching a predicate; supports type refinements. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.filter([1, 2, 3, 4], (n) => n % 2 === 0)))
// => [2, 4]
```

#### `forEach`

Runs a side-effecting callback for each element. A consumer; returns `void`.

```ts
import { Iterable } from "effect"

Iterable.forEach(["a", "b"], (x, i) => console.log(i, x))
// => 0 a
// => 1 b
```

#### `reduce`

Folds the iterable left-to-right into a single value. A consumer.

```ts
import { Iterable } from "effect"

console.log(Iterable.reduce([1, 2, 3, 4], 0, (acc, n) => acc + n))
// => 10
```

#### `scan`

Like `reduce`, but yields every intermediate accumulator (starting with the seed). Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.scan([1, 2, 3], 0, (acc, n) => acc + n)))
// => [0, 1, 3, 6]
```

#### `some`

Returns `true` if any element matches the predicate. Short-circuits on the first match.

```ts
import { Iterable } from "effect"

console.log(Iterable.some([1, 3, 4], (n) => n % 2 === 0))
// => true
```

#### `countBy`

Counts how many elements satisfy the predicate. A consumer.

```ts
import { Iterable } from "effect"

console.log(Iterable.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0))
// => 2
```

### Option and Result interop

#### `getSomes`

Keeps only the `Some` values from an iterable of `Option`s, unwrapping them. Lazy.

```ts
import { Array, Iterable, Option } from "effect"

console.log(
  Array.fromIterable(
    Iterable.getSomes([Option.some(1), Option.none(), Option.some(2)])
  )
)
// => [1, 2]
```

#### `getFailures`

Keeps only the failure values from an iterable of `Result`s. Lazy.

```ts
import { Array, Iterable, Result } from "effect"

console.log(
  Array.fromIterable(
    Iterable.getFailures([Result.succeed(1), Result.fail("err"), Result.succeed(2)])
  )
)
// => ["err"]
```

#### `getSuccesses`

Keeps only the success values from an iterable of `Result`s. Lazy.

```ts
import { Array, Iterable, Result } from "effect"

console.log(
  Array.fromIterable(
    Iterable.getSuccesses([Result.succeed(1), Result.fail("err"), Result.succeed(2)])
  )
)
// => [1, 2]
```

#### `flatMapNullishOr`

Maps with a function that may return `null` / `undefined`, dropping those results.
Handy with APIs like `Map.get`. Lazy.

```ts
import { Array, Iterable } from "effect"

const lookup = new Map([["a", 1], ["b", 2]])
const found = Iterable.flatMapNullishOr(["a", "x", "b"], (k) => lookup.get(k))
console.log(Array.fromIterable(found))
// => [1, 2]
```

### Zipping and pairing

#### `zip`

Pairs corresponding elements of two iterables; stops at the shorter one. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.zip([1, 2, 3], ["a", "b"])))
// => [[1, "a"], [2, "b"]]
```

#### `zipWith`

Like `zip`, but combines each pair with a function instead of tupling.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.zipWith([1, 2, 3], [10, 20, 30], (a, b) => a + b)))
// => [11, 22, 33]
```

#### `cartesian`

Every pair `[a, b]` across the two iterables (the cross product). Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.cartesian([1, 2], ["a", "b"])))
// => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
```

#### `cartesianWith`

Like `cartesian`, but combines each cross-product pair with a function.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.cartesianWith([1, 2], [10, 20], (a, b) => a * b)))
// => [10, 20, 20, 40]
```

#### `intersperse`

Inserts a separator between adjacent elements (none before the first or after the last).
Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.intersperse([1, 2, 3], 0)))
// => [1, 0, 2, 0, 3]
```

### Grouping and dedupe

#### `group`

Groups runs of **consecutive** equal elements (default `Equal` equivalence) into
non-empty arrays. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.group([1, 1, 2, 3, 3])))
// => [[1, 1], [2], [3, 3]]
```

#### `groupWith`

Like `group`, but with a custom equivalence function.

```ts
import { Array, Iterable } from "effect"

const grouped = Iterable.groupWith(
  ["a", "A", "b"],
  (x, y) => x.toLowerCase() === y.toLowerCase()
)
console.log(Array.fromIterable(grouped))
// => [["a", "A"], ["b"]]
```

#### `groupBy`

Groups **all** elements (not just consecutive ones) into a record keyed by `f`. A
consumer — it walks the whole iterable.

```ts
import { Iterable } from "effect"

console.log(Iterable.groupBy([1, 2, 3, 4], (n) => (n % 2 === 0 ? "even" : "odd")))
// => { odd: [1, 3], even: [2, 4] }
```

#### `dedupeAdjacent`

Collapses runs of adjacent equal elements (default `Equal` equivalence) to a single
element. Lazy.

```ts
import { Array, Iterable } from "effect"

console.log(Array.fromIterable(Iterable.dedupeAdjacent([1, 1, 2, 2, 3, 1])))
// => [1, 2, 3, 1]
```

#### `dedupeAdjacentWith`

Like `dedupeAdjacent`, but with a custom equivalence function.

```ts
import { Array, Iterable } from "effect"

const deduped = Iterable.dedupeAdjacentWith(
  ["Hello", "HELLO", "world"],
  (a, b) => a.toLowerCase() === b.toLowerCase()
)
console.log(Array.fromIterable(deduped))
// => ["Hello", "world"]
```

---

## The `NonEmptyIterable` module

A small module providing the `NonEmptyIterable<A>` type and the one operation that
exploits its guarantee.

### `NonEmptyIterable` (interface)

An `Iterable<A>` carrying a type-level brand (`readonly [nonEmpty]: A`) that proves at
least one element exists. It is structurally an `Iterable`, so it can be passed
anywhere one is expected; the brand only matters at compile time.

```ts
import { Array, NonEmptyIterable } from "effect"

// A plain iterable known to be non-empty is asserted into the branded type.
const ne = Array.make(1, 2, 3) as unknown as NonEmptyIterable.NonEmptyIterable<number>
```

### `unprepend`

Splits a non-empty iterable into its first element and an `Iterator` over the rest.
Safe because the type guarantees a head. Note the second element is a raw iterator
(stateful, already advanced past the head).

```ts
import { Array, NonEmptyIterable } from "effect"

const ne = Array.make(1, 2, 3) as unknown as NonEmptyIterable.NonEmptyIterable<number>
const [first, rest] = NonEmptyIterable.unprepend(ne)
console.log(first)
// => 1

// Wrap the iterator to consume the remaining elements.
console.log(Array.fromIterable({ [Symbol.iterator]: () => rest }))
// => [2, 3]
```