[英]Performing side effects using scala cats effect
我正在尝试在 Scala 中使用猫效果,并且在世界末日我有这样的类型: IO[Vector[IO[Vector[IO[Unit]]]]]
我发现只有一种方法来运行它:
for {
row <- rows.unsafeRunSync()
} yield
for {
cell <- row.unsafeRunSync()
} yield cell.handleErrorWith(errorHandlingFunc).unsafeRunSync()
但它看起来非常丑陋。 请帮助我了解如何执行复杂的副作用。
更新:
1)第一个IO
- 我打开 excel 文件并获取行向量,即IO[Vector[Row]]
。
2)第二次IO
- 我对每一行执行数据库查询。 我无法用Vector[_]
组合 IO monad,
3)第三个IO
- 我使用来自 DB 的Vector[Results]
为 excel 的每一行创建 PDF 文件。
所以我有这样的功能:
1) String=>IO[Vector[Row]]
2) Row=>IO[Vector[Results]]
3) Vector[Results] => IO[Unit]
举个例子,这是我刚刚用相同类型的头顶制作的一个无意义的动作:
import cats.effect.IO
val actions: IO[Vector[IO[Vector[IO[Unit]]]]] =
IO(readLine).flatMap(in => IO(in.toInt)).map { count =>
(0 until count).toVector.map { _ =>
IO(System.nanoTime).map { t =>
(0 until 2).toVector.map { _ =>
IO(println(t.toString))
}
}
}
}
这里我们从标准输入中读取一个字符串,将它解析为一个整数,多次查看当前时间,并且每次打印两次。
展平这种类型的正确方法是使用sequence
来重新排列图层:
import cats.implicits._
val program = actions.flatMap(_.sequence).flatMap(_.flatten.sequence_)
(或者类似的东西——你可以用很多合理的方式来写这个。)
该程序的类型为IO[Unit]
,并且按我们的预期工作:
scala> program.unsafeRunSync
// I typed "3" here
8058983807657
8058983807657
8058984254443
8058984254443
8058984270434
8058984270434
但是,每当您看到涉及多层IO
和集合的深度嵌套类型时,最好的做法很可能是首先避免陷入这种情况(通常使用traverse
)。 在这种情况下,我们可以像这样重写我们的原始actions
:
val actions: IO[Unit] =
IO(readLine).flatMap(in => IO(in.toInt)).flatMap { count =>
(0 until count).toVector.traverse_ { _ =>
IO(System.nanoTime).flatMap { t =>
(0 until 2).toVector.traverse { _ =>
IO(println(t.toString))
}
}
}
}
这将与我们的program
完全相同的方式工作,但是我们通过将原始actions
的map
替换为flatMap
或traverse
避免嵌套。 知道你需要什么是你通过练习学到的东西,但是当你开始时,最好尽可能地采取最小的步骤并遵循类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.