Reputation: 8043
While trying to play with Options in scala I have come across this peculiar problem.
I started off with creating a List[Option[Int]] as follows:
scala> List(Some(1),Some(2),None,Some(3))
res0: List[Option[Int]] = List(Some(1), Some(2), None, Some(3))
Then I tried to map an addition to 1 over the entries of the list in res0 as follows:
scala> res0 map (_ + 1)
This gave me the error:
<console>:9: error: type mismatch;
found : Int(1)
required: String
res0 map (_ + 1)
^
Then I tried flatMapping an addition over the entries as follows:
scala> res0 flatMap (_ + 1)
This gave me the same error:
<console>:9: error: type mismatch;
found : Int(1)
required: String
res0 flatMap (_ + 1)
^
But something like res0.flatMap(r => r)
works just fine with a result of:
res9: List[Int] = List(1, 2, 3)
Can anybody tell me why adding the entry to 1 would fail for both map and flatMap?
Upvotes: 1
Views: 1634
Reputation: 955
Try to use get to extract the value from Some[Int]
to Int
allowing for calculation value + 1
ie:
res0 map{_.getOrElse(0) + 1}
As pointed out by @Sepp2k you could alternatively use a collect
to avoid having a default for None
res0 collect {case Some(x) => x + 1 }
Upvotes: 1
Reputation: 12049
They are failing because the types are wrong and the compiler correctly states it as such.
The map case fails because map
expects a function A => B
. In your code, A => B
is really Int => Int
which will not work because calling map
on your list means that A
is actually Option[Int]
.
Furthermore, flatMap
expects a function of the form A => F[B]
. So you will get your answer if you did res0 flatMap { o => o map { a => a + 1 } }
. This basically is the expansion of:
for {
element <- res0 // o above
value <- element // a above
} yield value + 1
Upvotes: 1
Reputation: 12852
You try to invokee.+(1)
on every element e
in a List[Option[Int]]
, but +
is not a function declared by Option[_]
. String concatenation, however, would be possible (I assume there is an implicit from Any
to String
), but only if the second argument were a string as well (not sure why the implicit whose existence I assumed isn't considered here).
You can overcome this problem by doing working with a default value as suggested by @korefn, or "hide" the differentiation between Some(x)
and None
in another invocation of map
, namely by
map(_.map(_ + 1))
Upvotes: 1
Reputation: 297195
The first two things you tried failed because you are trying to add an Option
to an Int
, and that's not possible.
The weird error message happens because Scala assumes, since Option
doesn't have a +
method, that you are trying String
concatenation, but you'd have to either add an Option
to a String
, or a String
to an Option
, and you are doing neither, hence the error message.
In the last case, you are not trying to add anything, you are simply returning Option
as is, hence no error message.
Upvotes: 6
Reputation: 370162
Both the function given to flatMap
as well as the function given to map
take a value of the list's element type - in this case Option[Int]
. But your function _ + 1
expects an Int
, not an Option[Int]
, so you can't use it as the argument to either map
or flatMap
in this case. Further the function given to flatMap
should return an iterable¹, but your function would return a number.
This will do what you want: res0 flatMap (_ map (_ + 1))
. Here the function given to flatMap
takes an Option[Int]
and returns an Option[Int]
by calling map
on the option. flatMap
then takes the options returned by the function and concatenates them.
¹ Technically a GenTraversableOnce
.
Upvotes: 1
Reputation: 59994
To increment all values that are not None
, you need to map also each Option
element of the list, like so:
scala> res0.map(_.map(_ + 1))
res1: List[Option[Int]] = List(Some(2), Some(3), None, Some(4))
If you want to filter out the None
s, you would indeed use a flatMap
:
scala> res0.flatMap(_.map(_ + 1))
res2: List[Int] = List(2, 3, 4)
Upvotes: 1