3

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

Ben
  • 1,305
  • 2
  • 12
  • 18
Vadym Chekan
  • 3,943
  • 2
  • 27
  • 21

2 Answers2

3

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
Ben
  • 1,305
  • 2
  • 12
  • 18
2

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)
som-snytt
  • 38,672
  • 2
  • 41
  • 120