为了理解Scala中的IO-monad

时间:2017-11-22 16:05:02

标签: scala io scalaz

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

2 个答案:

答案 0 :(得分:1)

scala中

flatMap

回想一下,for-comprehensions只是对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转换因为它们适用于集合类型(和选项)(在我看来)令人困惑,因为它们允许您在不同类型的Monad 之间切换(例如列表/选项) /设置等)。例如,x的类型是什么?

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

scalaz中的Monads

仔细查看scalaz.Monad的{​​{1}}:

flatMap

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 的结果类型必须位于M[B]。虽然有时这可能有点刺激,但它具有完全可预测的优点。你永远不会对你理解的monad是什么感到困惑

回到问题

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

B

答案 1 :(得分:0)

iio必须属于同一个monad:

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