Reputation: 1994
Hey guys I got this ugly thing:
val test = Some(Map("TesT",123))
val keys = test.getOrElse(Map()).keys.map(_.toLowerCase).asInstanceOf[Set[String]]
require(keys.contains("test")
Can I turn it (line #2) into a clean/readable for comprehension?
Here's my attempt:
scala> val keys = for {
| map <- test
| keys <- map.keys
| k <- keys
| } yield k.toLowerCase
<console>:18: error: value toLowerCase is not a member of Char
} yield k.toLowerCase
^
<console>:16: error: type mismatch;
found : Iterable[Char]
required: Option[?]
keys <- map.keys
^
Upvotes: 2
Views: 304
Reputation: 8463
Your original:
val keys = for {
map <- test
keys <- map.keys
k <- keys
} yield k.toLowerCase
One constraint of the for comprehension over flatmap
and map
is that it requires the same kind of enumerator (really a monad) throughout, the first establishing which kind. In your example, the first enumerator is an Option
, so it expects map.keys
and keys
to be of type Option
as well.
Another problem with your example, is that keys
is really a single key
taken from the set map.keys
... so k
would then refer to a character in the enumurator across keys: String
.
Resolve the for-comprehension type problem by converting the initial type of the for
comprehension to a Seq
, allowing the following terms to be of that type (they are), and then stop after extracting the key
:
val keys = for {
map <- test.toSeq
key <- map.keys
} yield key.toLowerCase
Upvotes: 1
Reputation: 40500
You don't need a for comprehension for this. Clearly sequencing operations, and spelling the steps out explicitly is often more clear and readable. Just don't try to cram things into a single line:
test
.iterator
.flatMap(_.keys)
.map(_.toLowerCase)
.contains("test")
Upvotes: 3
Reputation: 1477
Comprehensions is just a syntactic sugar for map
/flatMap
. The flatMap
method of Option
returns another Option
. To get a multiple values you should start with sequence, so the first line should be map <- test.toSeq
. This explains the second error message.
The second line in the comprehension try to access keys
using flatMap
. It could be fixed in two ways. Either replaces it by val keys = map.keys
, so neither map
or flatMap
is involved, or remove this line completely in make a call on the third one: k <- map.keys
. This will fix fix the first error.
So you may choose between two solutions:
val keys = for {
map <- test.toSeq
val keys = map.keys
k <- keys
} yield k.toLowerCase
or
val keys = for {
map <- test.toSeq
k <- map.keys
} yield k.toLowerCase
Upvotes: 1