Hyperlinkv0.8.0-beta.28

NonEmptyIterable

NonEmptyIterable.unprependconsteffect/NonEmptyIterable.ts:212
<A>(self: NonEmptyIterable<A>): [
  firstElement: A,
  remainingElements: Iterator<A>
]

Extracts the first element and remaining elements from a non-empty iterable safely.

When to use

Use to split a non-empty iterable into its first element and an iterator for the remaining elements.

Details

This function provides a safe way to deconstruct a NonEmptyIterable into its head (first element) and tail (remaining elements as an iterator). Since the iterable is guaranteed to be non-empty, the first element is always available.

Example (Extracting first and remaining elements)

import { Array, Chunk, NonEmptyIterable } from "effect"

// Helper to make iterator iterable for Array.from
const iteratorToIterable = <T>(iterator: Iterator<T>): Iterable<T> => ({
  [Symbol.iterator]() {
    return iterator
  }
})

// With NonEmptyArray from Array.make (cast to NonEmptyIterable)
const numbers = Array.make(
  1,
  2,
  3,
  4,
  5
) as unknown as NonEmptyIterable.NonEmptyIterable<number>
const [first, rest] = NonEmptyIterable.unprepend(numbers)
console.log(first) // 1
console.log(globalThis.Array.from(iteratorToIterable(rest))) // [2, 3, 4, 5]

// With strings (assert when known to be non-empty)
const text = "hello" as unknown as NonEmptyIterable.NonEmptyIterable<string>
const [firstChar, restChars] = NonEmptyIterable.unprepend(text)
console.log(firstChar) // "h"
console.log(globalThis.Array.from(iteratorToIterable(restChars)).join("")) // "ello"

// With Sets (assert when known to be non-empty)
const uniqueNumbers = new Set([
  10,
  20,
  30
]) as unknown as NonEmptyIterable.NonEmptyIterable<number>
const [firstUnique, restUnique] = NonEmptyIterable.unprepend(uniqueNumbers)
console.log(firstUnique) // 10 (or any element, Set order is not guaranteed)
console.log(globalThis.Array.from(iteratorToIterable(restUnique))) // [20, 30] (in some order)

// With Maps (assert when known to be non-empty)
const keyValuePairs = new Map([["a", 1], ["b", 2], [
  "c",
  3
]]) as unknown as NonEmptyIterable.NonEmptyIterable<[string, number]>
const [firstPair, restPairs] = NonEmptyIterable.unprepend(keyValuePairs)
console.log(firstPair) // ["a", 1]
console.log(globalThis.Array.from(iteratorToIterable(restPairs))) // [["b", 2], ["c", 3]]

// With custom generators
function* fibonacci(): Generator<number> {
  let a = 1, b = 1
  yield a
  for (let i = 0; i < 10; i++) {
    yield b
    const next = a + b
    a = b
    b = next
  }
}

const generator = Chunk.fromIterable(
  fibonacci()
) as unknown as NonEmptyIterable.NonEmptyIterable<number>
const [firstFib, restFib] = NonEmptyIterable.unprepend(generator)
console.log(firstFib) // 1
console.log(globalThis.Array.from(iteratorToIterable(restFib))) // [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

// Practical usage: implementing reduce for non-empty iterables
function reduceNonEmpty<A, B>(
  data: NonEmptyIterable.NonEmptyIterable<A>,
  f: (acc: B, current: A) => B,
  initial: B
): B {
  const [first, rest] = NonEmptyIterable.unprepend(data)
  let result = f(initial, first)

  // Convert iterator to iterable for iteration
  const iterable = {
    [Symbol.iterator]() {
      return rest
    }
  }
  for (const item of iterable) {
    result = f(result, item)
  }

  return result
}

const data = Array.make(
  1,
  2,
  3,
  4
) as unknown as NonEmptyIterable.NonEmptyIterable<number>
const sum = reduceNonEmpty(data, (acc, x) => acc + x, 0) // 10
getters
export const unprepend = <A>(self: NonEmptyIterable<A>): [firstElement: A, remainingElements: Iterator<A>] => {
  const iterator = self[Symbol.iterator]()
  const next = iterator.next()
  if (next.done) {
    throw new Error(
      "BUG: NonEmptyIterator should not be empty - please report an issue at https://github.com/Effect-TS/effect/issues"
    )
  }
  return [next.value, iterator]
}