Vadym Chekan
Vadym Chekan

Reputation: 5157

For comprehension over Option array

I am getting compilation error:

Error:(64, 9) type mismatch;
 found   : Array[(String, String)]
 required: Option[?]
      y <- x
        ^

in a fragment:

val z = Some(Array("a"->"b", "c" -> "d"))
val l = for(
  x <- z;
  y <- x
) yield y

Why generator over Array does not produce items of the array? And where from requirement to have Option is coming from?

To be more ridiculous, if I replace "yield" with println(y) then it does compile.

Scala version: 2.10.6

Upvotes: 3

Views: 835

Answers (2)

Ben
Ben

Reputation: 1474

This is because of the way for expressions are translated into map, flatmap and foreach expressions. Let's first simplify your example:

val someArray: Some[Array[Int]] = Some(Array(1, 2, 3))
val l = for {
  array: Array[Int] <- someArray
  number: Int <- array
} yield number

In accordance with the relevant part of the Scala language specification, this first gets translated into

someArray.flatMap {case array => for (number <- array) yield number}

which in turn gets translated into

someArray.flatMap {case array => array.map{case number => number}}

The problem is that someArray.flatMap expects a function from Array[Int] to Option[Array[Int]], whereas we've provided a function from Array[Int] to Array[Int].

The reason the compilation error goes away if yield number is replaced by println(number) is that for loops are translated differently from for comprehensions: it will now be translated as someArray.foreach{case array => array.foreach {case item => println(item)}}, which doesn't have the same typing issues.

A possible solution is to begin by converting the Option to the kind of collection you want to end up with, so that its flatMap method will have the right signature:

val l = for {
  array: Array[Int] <- someArray.toArray
  number: Int <- array
} yield number

Upvotes: 3

som-snytt
som-snytt

Reputation: 39577

It's the usual "option must be converted to mix monads" thing.

scala> for (x <- Option.option2Iterable(Some(List(1,2,3))); y <- x) yield y
res0: Iterable[Int] = List(1, 2, 3)

Compare

scala> for (x <- Some(List(1,2,3)); y <- x) yield y
<console>:12: error: type mismatch;
 found   : List[Int]
 required: Option[?]
       for (x <- Some(List(1,2,3)); y <- x) yield y
                                      ^

to

scala> Some(List(1,2,3)) flatMap (is => is map (i => i))
<console>:12: error: type mismatch;
 found   : List[Int]
 required: Option[?]
       Some(List(1,2,3)) flatMap (is => is map (i => i))
                                           ^

or

scala> for (x <- Some(List(1,2,3)).toSeq; y <- x) yield y
res3: Seq[Int] = List(1, 2, 3)

Upvotes: 2

Related Questions