繁体   English   中英

用于理解 Scala 中的 IO-monad

[英]For comprehension with IO-monad in Scala

我的 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

iio必须属于同一个 monad:

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

flatMap斯卡拉

回想一下,for-comprehension 只是对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

因此编译错误。

再次在 Scala 中使用flatMap

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

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

scalaz 中的 Monad

仔细看看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

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

回到问题

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM