4

I have some code structurally identical to this and I'm not sure the best way to clean it up? The trivial IOs and additions are there so that the example compiles without needing additional methods.

I'd really like to not have it be so nested, is there a way to have a single for comprehension that supports both IO and List? I know theres OptionT for the option variant of this problem, but there doesn't seem to be an equivalent ListT.

Any advice would be greatly appreciated

import cats.Traverse
import cats.effect.IO
import cats.implicits._

def exampleDoingSomeThings: IO[Unit] = for {
    ids <- IO.pure(List(1, 2, 3))
    _ <- ids.traverse[IO, Unit](id => for {
      users <- IO.pure(List(id + 4, id + 5, id + 6))
      data <- IO(id + 7)
      otherData <- IO(id + 8)
      _ <- users.traverse[IO, Unit](ud => for {
        innerData <- IO(id + ud)
        innerState <- IO(ud + 9)
        _ <- if (innerState > 15) for {
          _ <- IO(println(s"action1: $id $ud"))
          _ <- IO(println(s"action2: $id $ud"))
        } yield () else IO.pure()
      } yield ())
    } yield ())
  } yield ()

exampleDoingSomeThings.unsafeRunSync

https://scalafiddle.io/sf/S79H1ZI/0

4

1 回答 1

3

正如其他人所提到的,您可以将您的方法提取到子方法中。但是,如果您觉得这还不够,您可以使用FS2Monix等库来让您的生活更轻松。它非常适合处理 IO + List 的事情。

您可以将流可视化为逐一发出的项目列表。因此,您一次只需要处理一个。

上面的例子可以翻译为(不包括未使用的变量):

莫尼克斯:

def monixThings: Observable[Unit] = for {
  id <- Observable.fromIterable(List(1, 2, 3))
  ud <- Observable.fromIterable(List(id + 4, id + 5, id + 6))
  innerState <- Observable.pure(ud + 9)
  _ <- Observable.fromTask {
    if (innerState > 15) {
      for {
        _ <- Task.delay(println(s"action1: $id $ud"))
        _ <- Task.delay(println(s"action2: $id $ud"))
      } yield ()
    } else {
      Task.unit
    }
  }
} yield ()

monixThings.completedL.runSyncUnsafe()

https://scalafiddle.io/sf/BDKbGCq/0

FS2:

import cats.effect.IO
import fs2.Stream

object FS2Example extends App {

  def fs2Things = for {
    id <- Stream.emits(List(1, 2, 3))
    ud <- Stream.emits(List(id + 4, id + 5, id + 6))
    innerState <- Stream.emit(ud + 9)
    _ <- Stream.eval {
      if (innerState > 15) {
        for {
          _ <- IO(println(s"action1: $id $ud"))
          _ <- IO(println(s"action2: $id $ud"))
        } yield ()
      } else {
        IO.unit
      }
    }
  } yield ()

  fs2Things.compile.drain.unsafeRunSync()
}
于 2019-11-27T08:40:54.077 回答