Hyperlinkv0.8.0-beta.28

Stream

Stream.zipWithArrayconsteffect/Stream.ts:3581
<AR, ER, RR, AL, A>(
  right: Stream<AR, ER, RR>,
  f: (
    left: Arr.NonEmptyReadonlyArray<AL>,
    right: Arr.NonEmptyReadonlyArray<AR>
  ) => readonly [
    output: Arr.NonEmptyReadonlyArray<A>,
    leftoverLeft: ReadonlyArray<AL>,
    leftoverRight: ReadonlyArray<AR>
  ]
): <EL, RL>(left: Stream<AL, EL, RL>) => Stream<A, EL | ER, RL | RR>
<AL, EL, RL, AR, ER, RR, A>(
  left: Stream<AL, EL, RL>,
  right: Stream<AR, ER, RR>,
  f: (
    left: Arr.NonEmptyReadonlyArray<AL>,
    right: Arr.NonEmptyReadonlyArray<AR>
  ) => readonly [
    output: Arr.NonEmptyReadonlyArray<A>,
    leftoverLeft: ReadonlyArray<AL>,
    leftoverRight: ReadonlyArray<AR>
  ]
): Stream<A, EL | ER, RL | RR>

Zips two streams by applying a function to non-empty arrays of elements.

Details

The function returns output plus leftover arrays that carry into the next pull.

Example (Zipping stream chunks)

import { Array, Console, Effect, Stream } from "effect"

const left = Stream.fromArrays([1, 2, 3], [4, 5])
const right = Stream.fromArrays(["a", "b"], ["c", "d", "e"])

const zipped = Stream.zipWithArray(left, right, (leftChunk, rightChunk) => {
  const minLength = Math.min(leftChunk.length, rightChunk.length)
  const output = Array.makeBy(minLength, (i) => [leftChunk[i], rightChunk[i]] as const)

  return [output, leftChunk.slice(minLength), rightChunk.slice(minLength)]
})

const program = Effect.gen(function*() {
  const result = yield* Stream.runCollect(zipped)
  yield* Console.log(result)
})

Effect.runPromise(program)
// Output: [[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"]]
zipping
Source effect/Stream.ts:358177 lines
export const zipWithArray: {
  <AR, ER, RR, AL, A>(
    right: Stream<AR, ER, RR>,
    f: (
      left: Arr.NonEmptyReadonlyArray<AL>,
      right: Arr.NonEmptyReadonlyArray<AR>
    ) => readonly [
      output: Arr.NonEmptyReadonlyArray<A>,
      leftoverLeft: ReadonlyArray<AL>,
      leftoverRight: ReadonlyArray<AR>
    ]
  ): <EL, RL>(left: Stream<AL, EL, RL>) => Stream<A, EL | ER, RL | RR>
  <AL, EL, RL, AR, ER, RR, A>(
    left: Stream<AL, EL, RL>,
    right: Stream<AR, ER, RR>,
    f: (
      left: Arr.NonEmptyReadonlyArray<AL>,
      right: Arr.NonEmptyReadonlyArray<AR>
    ) => readonly [
      output: Arr.NonEmptyReadonlyArray<A>,
      leftoverLeft: ReadonlyArray<AL>,
      leftoverRight: ReadonlyArray<AR>
    ]
  ): Stream<A, EL | ER, RL | RR>
} = dual(3, <AL, EL, RL, AR, ER, RR, A>(
  left: Stream<AL, EL, RL>,
  right: Stream<AR, ER, RR>,
  f: (
    left: Arr.NonEmptyReadonlyArray<AL>,
    right: Arr.NonEmptyReadonlyArray<AR>
  ) => readonly [
    output: Arr.NonEmptyReadonlyArray<A>,
    leftoverLeft: ReadonlyArray<AL>,
    leftoverRight: ReadonlyArray<AR>
  ]
): Stream<A, EL | ER, RL | RR> =>
  fromChannel(Channel.fromTransformBracket(Effect.fnUntraced(function*(_, scope) {
    const pullLeft = yield* Channel.toPullScoped(left.channel, scope)
    const pullRight = yield* Channel.toPullScoped(right.channel, scope)
    const pullBoth = Effect.gen(function*() {
      const fiberLeft = yield* Effect.forkIn(pullLeft, scope)
      const fiberRight = yield* Effect.forkIn(pullRight, scope)
      return (yield* Fiber.joinAll([fiberLeft, fiberRight])) as [
        Arr.NonEmptyReadonlyArray<AL>,
        Arr.NonEmptyReadonlyArray<AR>
      ]
    })

    type State =
      | { _tag: "PullBoth" }
      | { _tag: "PullLeft"; rightArray: Arr.NonEmptyReadonlyArray<AR> }
      | { _tag: "PullRight"; leftArray: Arr.NonEmptyReadonlyArray<AL> }
    let state: State = { _tag: "PullBoth" }

    const pull: Effect.Effect<
      Arr.NonEmptyReadonlyArray<A>,
      EL | ER | Cause.Done,
      RL | RR
    > = Effect.gen(function*() {
      const [left, right] = state._tag === "PullBoth"
        ? yield* pullBoth
        : state._tag === "PullLeft"
        ? [yield* pullLeft, state.rightArray]
        : [state.leftArray, yield* pullRight]
      const result = f(left, right)
      if (Arr.isReadonlyArrayNonEmpty(result[1])) {
        state = { _tag: "PullRight", leftArray: result[1] }
      } else if (Arr.isReadonlyArrayNonEmpty(result[2])) {
        state = { _tag: "PullLeft", rightArray: result[2] }
      } else {
        state = { _tag: "PullBoth" }
      }
      return result[0]
    })

    return pull
  }))))
Referenced by 3 symbols