Sohaib
Sohaib

Reputation: 4704

Scala - Flatmap a Seq of Options and Traversable

Consider a flatMap written over some case matching. For example:

list.flatMap( v =>
    v match {
        case Cond1 => if(something) Some(Int) else None
        //..Other conditions yielding Option[Int]
        case CondN => if(somethingelse) Seq(Int) else Seq()
    })

However this wont compile. If the seq is all of Option[Int] or all of Seq[Int] the flatMap works. But not if the Seq is a mix of Options and Seqs. Why is such a restriction in place? Does this solve a particular ambiguity that I cannot think of as of now.

EDIT1 Adding code snippet from REPL

scala> val a = Seq(Option(1), Seq(2,3))
a: Seq[Equals] = List(Some(1), List(2, 3))

scala> val b = Seq(Seq(1), Seq(2,3))
b: Seq[Seq[Int]] = List(List(1), List(2, 3))

scala> a.flatMap(x=>x)
<console>:9: error: type mismatch;
 found   : Equals
 required: scala.collection.GenTraversableOnce[?]
              a.flatMap(x=>x)
                           ^

scala> b.flatMap(x=>x)
res24: Seq[Int] = List(1, 2, 3)

EDIT2 After Filippo's answer I tried the following piece of code in the REPL and it worked.

scala> val options = Seq("opt1", "opt2")
options: Seq[String] = List(opt1, opt2)

scala> options.flatMap( x => 
     |      x match {
     |      case "opt1" => Some(1)
     |      case "opt2" => Seq(2,3)
     |      case _ => None
     |      })
res27: Seq[Int] = List(1, 2, 3)

How is the resolution different in each of the scenarios. More importantly when I map instead of flatMap the result is the same as the Seq a that I had created.

scala> options.map( x => 
 |      x match {
 |      case "opt1" => Some(1)
 |      case "opt2" => Seq(2,3)
 |      case _ => None
 |      })
res28: Seq[Equals] = List(Some(1), List(2, 3))  

Upvotes: 2

Views: 3288

Answers (1)

Filippo Vitale
Filippo Vitale

Reputation: 8113

Option is a GenTraversableOnce but scala needs some help here:

  val a: Seq[TraversableOnce[Int]] = Seq(Option(1), Seq(2,3))
  a.flatMap(x=>x)

  res0: Seq[Int] = List(1, 2, 3)

EDIT after additions to the question

I think that if the type of your sequence is the one you are expecting, everything boils down to the function passed to the flatMap. If scala can't figure out that the function is (A) => Traversable[A] when the starting sequence is Seq[A], I think we should make some types explicit.

Now, back to your first sample, I would refactor it as:

list.flatMap {
  case Cond1 if something     => Seq(Int)
  case CondN if somethingelse => Seq(Int)
  case _                      => Seq()
}

No doubt scala is now able to infer the types correctly.

Upvotes: 5

Related Questions