Search code examples
scalascala-cats

Can cats.effect.IO be sequenced, ie is it in the Traverse typeclass?


I like to sequence collections of effects eg to turn a List[IO[Int]] into a IO[List[Int]] like so :-

scala> import cats._, cats.data._, cats.implicits._, cats.effect._

scala> val efs : List[IO[Int]] = List(IO(1),IO(2))
efs: List[cats.effect.IO[Int]] = List(IO$647684131, IO$2021068036)

scala> var efOfInts = efs.sequence
efOfInts: cats.effect.IO[List[Int]] = <function1>

scala> efOfInts.unsafeRunSync
res2: List[Int] = List(1, 2)

But is it possible to go the other way? eg to turn a IO[List[Int]] into a List[IO[Int]] ?

I cant seem to find the implicits to add sequence onto IO so now I'm wondering if it is not possible to Traverse or Sequence IO?

Has anyone done this or know why it is not allowed?

Thanks.


Solution

  • No, it is not allowed.

    The whole idea of IO is that you cannot get values out of it without unsafeRunSync. There is no "peeking inside"

    Since Traversable also means Foldable, let's look at why something like foldLeft on IO breaks the looking inside rule.

    def foldLeft[A, B](fa: IO[A], b: B)(f: (B, A) => B): B
    

    So for example if we had an x: IO[Int] (which produces 2)

    foldLeft(x, 0)(_ + _), that would have to return us a 2. So we have peeked inside. foldLeft would have to unsafeRunSync, which breaks referential transparency.

    So for this (and other similar) reasons, you cannot have Traverse on IO.