I have the following in my 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
Why? What's wrong?
I expected the ii
is completely the same as i
. But it refuses to compile:
Error:(12, 11) type mismatch;
found : scalaz.effect.IO[List[String]]
required: scala.collection.GenTraversableOnce[scalaz.effect.IO[List[String]]]
lst <- io
flatMap
in scala
Recall that for-comprehensions are just sugared calls to 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]
...
Your question
Here is the signature of Iterator.flatMap
def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B]
But you were attempting to supply a function returning an IO[B]
:
lst <- io //You cannot just have `io` on the right here
hence the compilation error.
flatMap
in scala again
Scala's flatMap <~> for-comprehension
conversions as they apply to collection types (and Option) are (in my opinion) confusing as they allow you to switch between different types of Monad (e.g. List/Option/Set etc). For example, what is the type of x
here?
val x =
for {
i <- List(1, 2, 3)
j <- Option(i + 1)
k <- Stream(i, j)
} yield k
Monads in scalaz
Having a closer look at scalaz.Monad
's flatMap
:
trait Monad[M[_]] {
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
}
The type of M
is always fixed. That is, in this comprehension:
lazy val ma: M[A] = ???
for (a <- ma; b <- f(a)) yield b
The result type of the function f
must be in M[B]
for some B
. Whilst sometimes this can be a little irritating, it has the advantage of being completely predictable. You never get confused about what monad your for comprehension is in.
Back to the question
It is not obvious what you want, but here are a few suggestions:
i.toStream.sequence.map(flatten) //IO[Stream[String]]