Skip to content
Rohit edited this page Jan 3, 2017 · 20 revisions

Recap: flatMap

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)

Monads

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 with unit(x) = List(x)
  • Set is monad with unit(x) = Set(x)
  • Option is a monad with unit(x) = Some(x)
  • Generator is a monad with unit(x) = single(x)

flatMap is an operation on each of these types, whereas unit in Scala is different for each monad.

Maps and Monads

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)

Monad Laws

To qualify as a monad, a type has to satisfy three laws:

  1. Associativity:
m flatMap f flatMap g == m flatMap (x => f(x) flatMap g)
  1. Left unit:
unit(x) flatMap f == f(x)
  1. Right unit:
m flatMap unit == m

Try

Try is similar to Option. Where Option can have a value of something or none, Try can have a value of Success or Failure. It uses Java try in its implementation.

Whereas Option is a monad, Try is not since the left unit law fails.

Bullet-proof principle: An expression composed from Try, map, flatMap will never throw a non-fatal exception.

Conclusion:

We have seen that for-expressions are useful not only for collections. Many other types also define map, flatMap, and withFilter operations and with them for-expressions.

Examples: Generator, Option, Try.

Many types that define flatMaps are Monads. If they also define withFilter, then they are called Monads with Zero.

The three monad laws give useful guidance in the design of library APIs

Clone this wiki locally