Data structures with map and flatMap seem to be quite common. In fact there's a name that describe 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.
Example of Monads
flatMap is an operation on each of these types, whereas unit in Scala is different for each monad.
Monads and map
map can be defined for every monad as a combination of flatMap and unit:
To qualify as a monad, a type has to satisfy three laws:
Let's check the monad laws for Option. Here's flatMap for Option:
Need to show Some(x) flatMap f == f(x)
- Right Unit Raw
Need to show: opt flatMap Some == opt
- Associative Law
Need to show: opt flatMap f flatMap g == opt flatMap (x => f(x) flatMap g)
Let's check in with code review:
We have seen that monad-typed expressions are typically written as for expressions. What is the significance of the laws with respect to this?
1. Associativity says essentially that one can “inline” nested for expressions:
2. Right Unit Raw Says
3: Left unit does not have an analogue for for-expressions.
Another type: Try
In the later parts of this course we will need a type named Try. Try resembles Option, but instead of Some/None there is a Success case with a value and a Failure case that contains an exception:
Creating a Try
You can wrap up an arbitrary computation in a Try.
Just like with Option, Try-valued computations can be composed in for expresssions.
If computeX and computeY succeed with results Success(x) and Success(y), this will return Success(f(x, y)). If either computation fails with an exception ex, this will return Failure(ex).
Definition of flatMap and map on Try
Call this the “bullet-proof” principle.
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.
Many of the types defining flatMap are monads. (If they also define withFilter, they are called “monads with zero”). The three monad laws give useful guidance in the design of library APIs.