Scala Language
monaden
Zoeken…
Monade definitie
Informeel is een monade een container met elementen, genoteerd als F[_]
, vol met 2 functies: flatMap
(om deze container te transformeren) en unit
(om deze container te maken).
Veelvoorkomende bibliotheekvoorbeelden zijn List[T]
, Set[T]
en Option[T]
.
Formele definitie
Monad M
is een parametrisch type M[T]
met twee bewerkingen flatMap
en unit
, zoals:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
Deze functies moeten voldoen aan drie wetten:
- Associativiteit :
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
Dat wil zeggen, als de volgorde ongewijzigd is, kunt u de voorwaarden in willekeurige volgorde toepassen. Dus het toepassen vanm
opf
en vervolgens het toepassen van het resultaat opg
levert hetzelfde resultaat op als het toepassen vanf
opg
en vervolgens het toepassen vanm
op dat resultaat. - Linker eenheid :
unit(x) flatMap f == f(x)
Dat wil zeggen dat de eenheids-monade vanx
kaart gebracht overf
gelijk is aan het toepassen vanf
opx
. - Rechter eenheid :
m flatMap unit == m
Dit is een 'identiteit': elke monade die in kaart wordt gebracht tegen de eenheid zal een monade retourneren die gelijkwaardig is aan zichzelf.
Voorbeeld :
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
- Associativiteit :
(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)
- Linker eenheid
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Juiste eenheid
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true
Standaard collecties zijn monaden
De meeste standaardcollecties zijn monaden ( List[T]
, Option[T]
) of monade-achtig ( Either[T]
, Future[T]
). Deze collecties kunnen eenvoudig worden gecombineerd binnen for
begrip (wat een gelijkwaardige manier is om flatMap
transformaties te schrijven):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)
Het bovenstaande komt overeen met:
a flatMap {
i => b map {
j => i * j
}
}
Omdat een monade de datastructuur bewaart en alleen op de elementen binnen die structuur inwerkt, kunnen we eindeloze monadische datastructuren ketenen, zoals hier voor een begrip wordt getoond.