I am not very versed in Scala and sincerily I found the documentation hard to try to figure this out, but I was wondering if someone could explain to me why the difference in compilation of the following statements:
I can easily iterate over a set of strings and yield the elements.
scala> for(name <- Set("asd", "123")) yield name
val res2: scala.collection.immutable.Set[String] = Set(asd, 123)
But i can't do it inline if the Set is inside an Option
scala> for(names <- Some(Set("asd", "123")); name <- names) yield (name)
^
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
It happens because of for-yield
is just syntactic sugar for flatMap
, map
and withFilter
functions. So, your code:
for(names <- Some(Set("asd", "123")); name <- names) yield (name)
actually is the same as:
Some(Set("asd", "123")).flatMap{ names: Set[String] =>
names.flatMap{ name: String =>
name // return type is String, but Set[(of some )B] is expected
}
}// return type is Set[String] but Option[(of some) C] is expected
look at the Option
flatMap
function:
@inline final def flatMap[B](f: A => Option[B]): Option[B]
but your f
returns Set[String]
as a result, compiler tell you about type missmatch (Set[String] != Option[?]
):
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
you should remember about type of the first statement in for-yield
construction. In your case it's names <- Some(Set("asd", "123"))
. It has type Option[Set[String]]
, so you should use only Option[T]
in x <- yourNextStatement
lines (x
should has Option[T]
type).
In conclusion:
Be careful with mixing different container types in for-yield
constructions. If you have some problems, just try to unwrap your for-yield
into combination of flatMap
, map
, withFilter
functions.
If you want to mix containers in for-yeild
, you should start another for-yield for each-container type. For example:
for {
names <- Some(Set("asd", "123"))
// will return Option[String]
reducedNames <- (for {
name <- names // here will be used Seq flatMap function, not Option
} yield (name + "some_suffix"))
.reduceLeftOption(_ + _) // here we will get Option[String] from Seq[String]
} yield reducedNames // will return Option[String]