有没有办法在不运行的情况下将内容从IO提升到其他容器?

时间:2019-09-12 00:47:39

标签: scala monad-transformers scala-cats io-monad cats-effect

根据cats官方文档:https://typelevel.org/cats-effect/typeclasses/liftio.html,如果我们想将某物从IO提升到其他容器,则应实现LiftIO特性,但是该示例显式运行unsafeRunXXX方法来获取效果,我想知道这是转换的唯一方法吗?

1 个答案:

答案 0 :(得分:3)

IO正在挂起副作用,并且其类型告诉您如果运行所有计算(包括副作用和纯计算)将获得什么值,如果最终没有错误的话(它们可以一路处理)。

这样,如果不运行计算就无法获得该值。因此,从IO[A]F[A]的任何有用翻译基本上都必须在某个地方调用一些.unsafeXXXunsafe部分并不意味着您不应该使用它-这意味着您需要知道自己在做什么,在您运行它的那一刻,返回的结果将是副作用,可能会失败,并且通常您会放弃参照透明性。

这就是为什么它在IOApp内部使用的原因(它在世界的尽头使用,您想在其中计算结果)。如果您知道IO,也可以将F转换为另一个F,而不会失去参照的透明度:

  • 像IO一样懒惰
  • 允许像IO一样暂停副作用,
  • 处理错误,就像IO。

因此,基本上,这是同一概念的另一种实现-参见:SyncIOCoevalTask,ZIO ...

// example: Async can be used to translate IO into F
def IO2F[F[_]: Async]: IO ~> F = new (IO ~> F) {
  def apply[A](ioa: IO[A]): F[A] = Async[F].async(ioa.unsafeRunAsync)
}

您还可以执行诸如IO[A] => Either[Throwable, A]IO[A] => Option[A]IO[A] => Future[A]之类的操作,但是您必须记住,每次进行此类评估时,都会立即开始产生副作用。

长话短说:要想将IO转换为其他内容,必须在某个地方使用.unsafeXXX,这还不错,unsafe只是在提醒您要小心,就是这样。