Monads
Monad Definition
Informally, a monad is a container of elements, notated as F[_], packed with 2 functions: flatMap (to transform this container) and unit (to create this container).
Common library examples include List[T], Set[T] and Option[T].
Formal definition
Monad M is a parametric type M[T] with two operations flatMap and unit, such as:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]These functions must satisfy three laws:
- Associativity:
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
That is, if the sequence is unchanged you may apply the terms in any order. Thus, applyingmtof, and then applying the result togwill yield the same result as applyingftog, and then applyingmto that result. - Left unit:
unit(x) flatMap f == f(x)
That is, the unit monad ofxflat-mapped acrossfis equivalent to applyingftox. - Right unit:
m flatMap unit == m
This is an ‘identity’: any monad flat-mapped against unit will return a monad equivalent to itself.
Example:
val m = List(1, 2, 3)
def unit(x: Int): List[Int] = List(x)
def f(x: Int): List[Int] = List(x * x)
def g(x: Int): List[Int] = List(x * x * x)
val x = 1- Associativity:
(m flatMap f).flatMap(g) == m.flatMap(x => f(x) flatMap g) //Boolean = true
//Left side:
List(1, 4, 9).flatMap(g) // List(1, 64, 729)
//Right side:
m.flatMap(x => (x * x) * (x * x) * (x * x)) //List(1, 64, 729)
- Left unit
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Right unit
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = trueStandard Collections are Monads
Most of the standard collections are monads (List[T], Option[T]), or monad-like (Either[T], Future[T]). These collections can be easily combined together within for comprehensions (which are an equivalent way of writing flatMap transformations):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)The above is equivalent to:
a flatMap {
i => b map {
j => i * j
}
}Because a monad preserves the data structure and only acts on the elements within that structure, we can endless chain monadic datastructures, as shown here in a for-comprehension.