Монади и функтори

Предния път – Type classes

  • моделират типове (а не просто обекти)
  • аксиомите (type class laws) са важни
  • позволяват ретроактивен ad hoc полиморфизъм
  • в Scala са реализирани чрез implicits и съответно могат да са контекстно-зависими

Ефекти

  • Option[A] – частичност
  • Try[A] – успех/грешка с изключение
  • Either[E, A] – успех/грешки
  • Validated[E, A] – валидация с множествено грешки
  • List[A] – недетерминизъм, множественост
  • IO[A] – вход/изход
  • Future[A] – (eager) асинхронност
  • Task[A] – (lazy) асихронност
  • Stream[A] – lazy поток
  • State[S, A] – състояние
  • Iteratee[I, O] – консуматор на поток
  • DBAction[A] – заявка/действие върху базата

Операции върху ефекти

Пренесохме възможността за тези операции върху ефекта Future
(и стойността в него)

  • map – трансформация на единична стойност (напр. val c = -a)
  • map2 (или zipMap) – трансформация на две независими стойности (val c = a + b). Резултатът c зависи от тях
  • map3, zipMap3…; mapN дефинира зависимости
  • flatMap – ефектна трансформация на единична стойност

Нека да генерализираме тези операции в type class-ове

Ще започнем от една различна гледна точка

Композиция на функции

Нека имаме функции f: A => B и g: B => C

Тогава h(x) = g(f(x)) е функция от тип A => C

h = g ∘ f

Композитност на функции – аксиоми

  • асоциативност – нека f: A => B, g: B => C и h: C => D. Тогава:

    (h ∘ g) ∘ f = h ∘ (g ∘ f)
  • неутрален елемент – нека identity = x => x. Тогава ∀ f

    identity ∘ f = f ∘ identity = f

Композитност на функции

h ∘ g ∘ f

Ефектни функции

Функция, връщаща стойност, затворена в ефект

A => Option[B]
A => Future[B]
A => Validated[E, B]

Композитност на ефектни функции?

Нека
f: A => Option[B],
g: B => Option[C],
h: C => Option[D]

h ∘ g ∘ f?

За всеки ефект имплементацията е различна

Option, ако нямаме flatMap

Често срещано при работа с някои езикови елементи (null, callback hell код, …)

Type class за композиране

Монада

Тук F е конструктор на тип, а не тип

Пример: List е конструктор на тип, List[Int] е тип

F е higher-kinded type (тип от по-висок ред)

higher-kinded polymorphism

Монада – аксиоми

  • асоциативност:

    compose(compose(f, g), h) == compose(f, compose(g, h))
  • неутрален елемент

    compose(unit, f) == compose(f, unit) == f

Монада за Option

Алтернативна дефиниция
чрез flatMap

flatMap може да се изрази чрез compose като:

unit, map и flatten са трети възможен набор от основни операции

Аксиомите чрез flatMap

  • асоциативност:

    Нека m: F[A] и f: A => B, g: B => C. Тогава

    m.flatMap(f).flatMap(g) == m.flatMap(a => f(a).flatMap(g))
  • ляв идентитет:

    ∀a: A и f: A => B е изпълнено: unit(a).flatMap(f) == f(a)
  • десен идентитет:

    ∀m: F[A] е изпълнено: m.flatMap(unit) == m 

for в Scala е монадна композиция

преобразува се до:

State монада

Генерализация на монадите – функтори

Еквиваленти в Cats

Композитност на функтори и монади

Функторите могат да бъдат композирани:

В общия случай монадите не могат да се композират. Но много могат

Това води до нуждата от специфични монадни трансформатори

Например OptionT за монади от Option
(тоест M[Option[_]], където M е монада)

Нули на монади

mZero: F[A] наричаме нула за монадата F, ако:

MonadFilter

Functional Programming in Scala

Теория на категориите