Scala Language
Монады
Поиск…
Определение Монады
Неофициально монада представляет собой контейнер элементов, обозначенный как F[_]
, заполненный двумя функциями: flatMap
(для преобразования этого контейнера) и unit
(для создания этого контейнера).
Примеры общей библиотеки включают List[T]
, Set[T]
и Option[T]
.
Формальное определение
Monad M
является параметрическим типом M[T]
с двумя операциями flatMap
и unit
, такими как:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
Эти функции должны удовлетворять трем законам:
- Ассоциативность :
(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
То есть, если последовательность не изменяется, вы можете применять термины в любом порядке. Таким образом, применяяm
кf
, а затем применяя результат кg
получите тот же результат, что и применениеf
кg
, а затем применитеm
к этому результату. - Левая единица :
unit(x) flatMap f == f(x)
То есть единичная монадаx
плоская картаf
, эквивалентна применениюf
кx
. - Правый блок :
m flatMap unit == m
Это «личность»: любая монада, сопоставленная с единицей, вернет монаду, эквивалентную самому себе.
Пример :
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
- Ассоциативность :
(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)
- Левая единица
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
- Правый блок
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true
Стандартные коллекции - Monads
Большинство стандартных коллекций являются монадами ( List[T]
, Option[T]
) или monad-like ( Either[T]
, Future[T]
). Эти коллекции могут быть легко объединены вместе for
понимания (которые являются эквивалентным способом написания преобразований flatMap
):
val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
i <- a
j <- b
} yield(i * j)
Вышеупомянутое эквивалентно:
a flatMap {
i => b map {
j => i * j
}
}
Поскольку монада сохраняет структуру данных и действует только на элементы внутри этой структуры, мы можем бесконечно цепные монадические структуры данных, как показано здесь для понимания.