Reputation: 107
def map[B] (f: A=>B) : Option[B]
def flatMap[B] (f: A=>Option[B]) : Option[B]
def map2[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C) :Option[C] =
ao.flatMap(aa=>
bo.map(bb=>
(f(aa,bb))))
Here is the definition of map and flatMap in Exception Handling and I have this map2 formed on the basis of map and flatMap. It is really hard to understand the formation of map2. Can some one explain the role of flatMap and map in map2. Thank you
Upvotes: 4
Views: 1607
Reputation: 11306
I think about things like this step by step from the result.
Firstly you know you eventually want a value of type A and a value of type B to pass to the function f.
Where does the A come from? We can access it by mapping over oa.
We can take that A and do the same to get B. mapping over ob gives us a B.
If you type this out in your IDE you will see a type error, you have an option option instead of an option.
This happened because that first map wraps its response as an option but so does the inner map. So by changing the outer map to flatMap you flatten it again.
Upvotes: 0
Reputation: 23788
Here is another attempt at explaining it. Option
is a Monad which in a simplified way might be seen as a generic container that hold some value(s).
map
is a transformation operation that allows you to transform value(s) inside the monad using simple function on "raw" types.
flatMap
is similar to map
but is a bit more complicated: it allows you to transform value(s) inside the monad using a function that accepts "raw" value but returns an instance of the same monad and still as a result you get just a Monad[B]
instead of Monad[Monad[B]]
that would be generated by the map
. In other words flatMap
"flattens" the result.
So now what your map2
does? It accepts 2 instances of Option
monad and a function that transform "raw" pair of types into a single new "raw" type and return Option
of that result type. Logically this is similar to map
but to implement it you need a flatMap
. To call your f
you need to "unpack" both ao
and bo
. But monad doesn't provide a way to just "unpack" raw value. You might want to use just map
. After all map2
is logically similar to it! However, if you write
ao.map(aa =>
bo.map(bb => f(aa,bb)))
as you might naively do, it wouldn't work as you might expect. The reason is that bo.map(bb => f(aa,bb))
returns Option[C]
(remember, there is no standard way to "unpack" a monad) and thus your function passed to ao.map(aa => ...)
returns Option[C]
and thus the result would be Option[Option[C]]
. But this exactly where flatMap
comes to the rescue! It allows you "unpack" this double Option
into a simple Option[C]
.
Obviously this explanation is quite naive but I hope it will help you get some intuition about what happens.
Upvotes: 2
Reputation: 23502
If you add some syntactic sugar using a for-comprehension
it suddenly becomes a lot more easy to read if you ask me:
def map2[A,B,C] (ao: Option[A], bo: Option[B])(f: (A,B) => C): Option[C] = for {
a <- ao
b <- bo
} yield f(a,b)
Basically, we want to extract the a
and the b
of our two options and then apply our function f
to get a C
. flatMap
allows us to do just that, by using a function from an A
to an Option[B]
. map
then allows us to apply our function f
to transform (A,B)
to C
.
Upvotes: 2