-
Notifications
You must be signed in to change notification settings - Fork 11
Monads
flatMap is a combinator that combines mapping and flattening. flatMap takes a function that works on the nested lists and then concatenates the results back together.
// Example 1
val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers.flatMap(x => x.map(_ * 2)) //Output: List(2, 4, 6, 8)
// Example 2
val fruits = Seq("apple", "banana", "orange")
fruits.map(_.toUpperCase) // List(APPLE, BANANA, ORANGE)
fruits.map(_.toUpperCase).flatten // List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)
fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)
Some reading: http://debasishg.blogspot.com/2008/03/monads-another-way-to-abstract.html. Simply put, Monad is a concept, an abstract interface if you will, that simply defines a way of composing data.
Data structures with map
and flatMap
seem to be quite common. In fact there’s a name that describes this class of a data structures together with some algebraic laws that they should have. They are called monads.
A monad M
is a parametric type M[T]
with two operations, flatMap
and unit
, that have to satisfy some laws.
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
In the literature, flatMap
is more commonly called bind
.
Examples:
-
List
is a monad withunit(x) = List(x)
-
Set
is monad withunit(x) = Set(x)
-
Option
is a monad withunit(x) = Some(x)
-
Generator
is a monad withunit(x) = single(x)
flatMap
is an operation on each of these types, whereas unit
in Scala is different for each monad.
map
can be defined for every monad as a combination of flatMap
and unit
:
m map f == m flatMap (x => unit(f(x)))
// OR
m map f == m flatMap (f andThen unit)
To qualify as a monad, a type has to satisfy three laws:
- Associativity:
m flatMap f flatMap g == m flatMap (x => f(x) flatMap g)
- Left unit:
unit(x) flatMap f == f(x)
- Right unit:
m flatMap unit == m