我有一些与此结构相同的代码,我不确定清除它的最佳方法吗?那里有一些琐碎的IO和附加功能,因此示例无需任何其他方法即可编译。
我真的不想让它如此嵌套,有没有一种方法可以使单个理解同时支持IO和List?我知道有OptionT可以解决此问题,但是似乎没有等效的ListT。
任何建议将不胜感激
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
答案 0 :(得分:1)
正如其他人所提到的,您可以将方法提取为子方法。但是,如果发现这还不够,可以使用FS2或Monix之类的库来简化生活。处理IO + List东西真的很好。
您可以将流可视化为逐一发出的项目列表。因此,您一次只需要处理一个即可。
上面的示例可以解释为(不包括未使用的变量):
Monix:
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()
}