Scala Language
Mónadas
Buscar..
Definición de la mónada
Informalmente, una mónada es un contenedor de elementos, anotados como F[_]
, empaquetados con 2 funciones: flatMap
(para transformar este contenedor) y unit
(para crear este contenedor).
Los ejemplos de bibliotecas comunes incluyen List[T]
, Set[T]
y Option[T]
.
Definicion formal
La mónada M
es un tipo paramétrico M[T]
con dos operaciones flatMap
y unit
, como:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
Estas funciones deben cumplir tres leyes:
- Asociatividad :
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
Es decir, si la secuencia no se modifica, puede aplicar los términos en cualquier orden. Por lo tanto, aplicarm
af
, y luego aplicar el resultado ag
dará el mismo resultado que aplicarf
ag
, y luego aplicarm
a ese resultado. - Unidad izquierda :
unit(x) flatMap f == f(x)
Es decir, la unidad de la mónada dex
asignada de forma plana a través def
es equivalente a aplicarf
ax
. - Unidad derecha :
m flatMap unit == m
Esta es una "identidad": cualquier mónada con plano mapeado contra unidad devolverá una mónada equivalente a sí misma.
Ejemplo :
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
- Asociatividad
(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)
- Unidad izquierda
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Unidad derecha
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true
Las colecciones estándar son mónadas
La mayoría de las colecciones estándar son mónadas ( List[T]
, Option[T]
), o similares a mónadas ( Either[T]
, Future[T]
). Estas colecciones se pueden combinar fácilmente dentro for
comprensiones (que son una forma equivalente de escribir transformaciones de flatMap
):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)
Lo anterior es equivalente a:
a flatMap {
i => b map {
j => i * j
}
}
Debido a que una mónada conserva la estructura de datos y solo actúa sobre los elementos dentro de esa estructura, podemos construir estructuras de datos monádicas en cadena sin fin, como se muestra aquí en una para comprensión.