IllSc
IllSc

Reputation: 1459

How to convert a `List[IO[Unit]]` into `Stream[IO,Unit]`

I have a List[IO[Unit]] which consists of distinct works encoded in IO. I would like to convert it into Stream[IO,Unit]

Currently, what I have done is this

val works: List[IO[Unit]]
works.map(work => Stream.eval(work)).reduceLeft((left, right) => left ++ right)

Is there a better way?

Upvotes: 2

Views: 920

Answers (2)

Oleg Pyzhcov
Oleg Pyzhcov

Reputation: 7353

I suggest doing one of those:

Stream.emits(works).flatMap(Stream.eval) // or
Stream.emits(works).evalMap(x => x) // which is the same, or
Stream(works: _*).evalMap(x => x) // which is also the same

There's a difference vs. doing Stream.evals on a works.sequence in that you lose the fact that your effect is made of different parts. That will surface itself if you run stream partially, e.g. by doing:

stream.take(3).compile.drain

If you do not sequence, it will only run first 3 elements from works. If you do, it will run all of them.

From other options proposed by Luis Miguel, only the unfoldEval one preserves the separation, but it's probably an overkill.

Upvotes: 3

I can think of these three alternatives:
(Note, I just checked they typecheck but I didn't run them)

def stream1: Stream[IO, Unit] =
  Stream.evalSeq(works.sequence)

def stream2: Stream[IO, Unit] =
  Stream.evals(works.sequence)

def stream3: Stream[IO, Unit] =
  Stream.unfoldEval(works) {
    case work :: tail =>
      work.map { io =>
        Some(io -> tail)
      }

    case Nil =>
      IO.pure(None)
  }

BTW, if you got that List[IO[Unit]] after a map.

You can data.traverse(f) instead of works.map(f).sequence
And f(input).map { io => instead of work.map { io =>

Upvotes: 3

Related Questions