我的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
为什么呢?怎么了?
我预计ii
与i
完全相同。但它拒绝编译:
Error:(12, 11) type mismatch;
found : scalaz.effect.IO[List[String]]
required: scala.collection.GenTraversableOnce[scalaz.effect.IO[List[String]]]
lst <- io
答案 0 :(得分:1)
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)
i
和io
必须属于同一个monad:
io <- i // i is an Iterator[...]
lst <- io // io is an IO[List[String]]