Some Name
Some Name

Reputation: 9521

For comprehension with IO-monad in Scala

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

Upvotes: 3

Views: 1270

Answers (3)

fileyfood500
fileyfood500

Reputation: 1321

When using IO and for-comprehensions, one option is to use .unsafeToFuture in your for comprehension. In your example, this would be:

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

Upvotes: 1

oxbow_lakes
oxbow_lakes

Reputation: 134270

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]]

Upvotes: 1

Stefan
Stefan

Reputation: 217

i and io must be of the same monad:

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

Upvotes: 1

Related Questions