Scala Language
Monady
Szukaj…
Definicja Monady
Nieformalnie monada jest kontenerem elementów oznaczonym jako F[_]
i zawiera 2 funkcje: flatMap
(do przekształcenia tego kontenera) i unit
(do utworzenia tego kontenera).
Typowe przykłady bibliotek obejmują List[T]
, Set[T]
i Option[T]
.
Formalna definicja
Monada M
to parametryczny typ M[T]
z dwiema operacjami flatMap
i unit
, takimi jak:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
Funkcje te muszą spełniać trzy prawa:
- Łączność:
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
Oznacza to, że jeśli sekwencja nie ulegnie zmianie, możesz zastosować warunki w dowolnej kolejności. Zatem zastosowaniem
dof
, a następnie zastosowanie wyniku dog
da taki sam wynik, jak zastosowanief
dog
, a następnie zastosowaniem
do tego wyniku. - Lewa jednostka :
unit(x) flatMap f == f(x)
Oznacza to, że monada jednostkowax
płasko zmapowana w poprzekf
jest równoważna zastosowaniuf
dox
. - Prawa jednostka :
m flatMap unit == m
Jest to „tożsamość”: każda monada płasko odwzorowana przeciwko jednostce zwróci monadę odpowiadającą jej samej.
Przykład :
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
- Stowarzyszenie :
(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)
- Lewa jednostka
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Właściwa jednostka
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true
Kolekcje standardowe to Monady
Większość standardowych kolekcji to monady ( List[T]
, Option[T]
) lub monadopodobne ( Either[T]
, Future[T]
). Te zbiory można łatwo łączyć ze sobą w for
zrozumienia (które są równoważnym sposobem pisania transformacji flatMap
):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)
Powyższe jest równoważne z:
a flatMap {
i => b map {
j => i * j
}
}
Ponieważ monada zachowuje strukturę danych i działa tylko na elementy w tej strukturze, możemy w nieskończoność łańcuchować monadyczne struktury danych, jak pokazano tutaj dla zrozumienia.