【问题标题】:For comprehension with IO-monad in Scala在 Scala 中理解 IO-monad
【发布时间】:2018-05-06 10:52:20
【问题描述】:

我的 Scala 中有以下内容

import scalaz.effect.IO
val i: Iterator[IO[List[String]]] = null

val ii: Iterator[IO[List[String]]] = for{ //This does not compile
  io <- i;
  lst <- io
} yield lst

为什么?怎么了?

我预计iii 完全相同。但它拒绝编译:

Error:(12, 11) type mismatch;
 found   : scalaz.effect.IO[List[String]]
 required: scala.collection.GenTraversableOnce[scalaz.effect.IO[List[String]]]
      lst <- io

【问题讨论】:

    标签: scala io scalaz


    【解决方案1】:

    使用 IO 和 for-comprehensions 时,一种选择是在您的 for comprehension 中使用 .unsafeToFuture。在您的示例中,这将是:

    val ii: Iterator[IO[List[String]]] = for{ 
      io <- i;
      lst <- io.unsafeToFuture()
    } yield lst
    

    【讨论】:

      【解决方案2】:

      flatMap 在 Scala 中

      回想一下,理解只是对flatMap 的甜蜜调用:

      for {
        a <- expr  //expr must return M[A] such that M has a 
                   //flatMap method: flatMap[B](f: A => N[B]) for some N
      
        b <- f(a)  //f(a) must be an N[B]
        ...
      

      您的问题

      这是Iterator.flatMap的签名

      def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B]
      

      但您试图提供一个返回 IO[B] 的函数:

      lst <- io //You cannot just have `io` on the right here
      

      因此编译错误。

      flatMap 再次在 Scala 中

      Scala 的 flatMap &lt;~&gt; for-comprehension 转换应用于集合类型(和选项)(在我看来)令人困惑,因为它们允许您在不同类型的 Monad 之间切换(例如 List/Option/Set等等)。比如这里x的类型是什么?

      val x = 
        for  {
          i <- List(1, 2, 3)
          j <- Option(i + 1)
          k <- Stream(i, j)
        } yield k
      

      scalaz 中的单子

      仔细查看scalaz.MonadflatMap

      trait Monad[M[_]] {
        def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
      }
      

      M 的类型始终是固定的。也就是说,在这种理解中:

      lazy val ma: M[A] = ???
      for (a <- ma; b <- f(a)) yield b
      

      函数f的结果类型某些B必须在M[B]。虽然有时这可能会有点烦人,但它具有完全可预测的优势。你永远不会对 你的 for 理解在什么 monad 中感到困惑。

      回到问题

      你想要什么并不明显,但这里有一些建议:

      i.toStream.sequence.map(flatten) //IO[Stream[String]]
      

      【讨论】:

        【解决方案3】:

        iio 必须属于同一个 monad:

        io <- i   // i is an Iterator[...]
        lst <- io // io is an IO[List[String]]
        

        【讨论】:

        • 不太明白...什么意思?
        猜你喜欢
        • 2018-05-05
        • 1970-01-01
        • 1970-01-01
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多