Scala Language
Monaden
Suche…
Monade-Definition
Informell handelt es sich bei einer Monade um einen Container mit Elementen, der als F[_]
, und enthält zwei Funktionen: flatMap
(um diesen Container zu transformieren) und unit
(um diesen Container zu erstellen).
Übliche Bibliotheksbeispiele sind List[T]
, Set[T]
und Option[T]
.
Formale Definition
Monade M
ist ein parametrischer Typ M[T]
mit zwei Operationen flatMap
und unit
, wie:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
Diese Funktionen müssen drei Gesetze erfüllen:
- Assoziativität :
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
Das heißt, wenn die Reihenfolge unverändert ist, können Sie die Bedingungen in beliebiger Reihenfolge anwenden. Wenn Sie alsom
auff
anwenden und dann das Ergebnis aufg
anwenden, erhalten Sie dasselbe Ergebnis wie das Anwenden vonf
aufg
und das anschließende Anwenden vonm
auf dieses Ergebnis. - Linke Einheit :
unit(x) flatMap f == f(x)
Das heißt, die Einheitsmonade vonx
flach überf
abgebildet ist, entspricht der Anwendung vonf
aufx
. - Rechte Einheit :
m flatMap unit == m
Dies ist eine 'Identität': Jede gegen Einheit gemappte Monade gibt eine Monade zurück, die ihrer selbst entspricht.
Beispiel :
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
- Assoziativität :
(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)
- Linke Einheit
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Rechte Einheit
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true
Standardsammlungen sind Monaden
Die meisten Standardsammlungen sind Monaden ( List[T]
, Option[T]
) oder monadenähnlich ( Either[T]
, Future[T]
). Diese Sammlungen können leicht miteinander kombiniert werden , in for
Comprehensions (welche eine äquivalente Art des Schreibens flatMap
Transformations):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)
Das obige ist äquivalent zu:
a flatMap {
i => b map {
j => i * j
}
}
Da eine Monade die Datenstruktur bewahrt und nur auf die Elemente innerhalb dieser Struktur einwirkt, können wir endlose monadische Datenstrukturen verketten, wie hier zum Verständnis gezeigt.