Slide 1

Slide 1 text

О монадах по-человечески Кирилл Бяков

Slide 2

Slide 2 text

2

Slide 3

Slide 3 text

3

Slide 4

Slide 4 text

Монада — практический подход 4

Slide 5

Slide 5 text

Проблема 1: слабая читаемость static int getFirstActualTimeIndex(List times) { int start = -1; for (int position = 0; position < times.size(); position++) { if (times.get(position).compareTo(new Date()) >= 0) { start = position; break; } } return start; } 5

Slide 6

Slide 6 text

Проблема 2: неясен момент завершения static int getFirstActualTimeIndex(List times) { int start = -1; for (int position = 0; position < times.size(); position++) { if (times.get(position).compareTo(new Date()) >= 0) { start = position; break; } } return start; } 6

Slide 7

Slide 7 text

Проблемы ● слабая читаемость ● недетерминированный флоу ● небезопасное изменение стейта 7

Slide 8

Slide 8 text

Imperative vs Declarative ● переход от императивной парадигмы к декларативной позволяет писать более безопасный и предсказуемый код 8 ● алгоритм состоит из последовательных шагов: не то, как ты это делаешь, а что именно ● такой код легче читается и более краток

Slide 9

Slide 9 text

Решение 1: в лоб, используя Rx static int getFirstActualTimeIndex(List times) { int index = 0; return Observable.fromIterable(times) .map(time -> Pair.create(index++, time)) .filter(data -> data.second.compareTo(new Date()) >= 0) .map(data -> data.first) .firstElement() .toSingle(-1) .blockingGet(); } 9

Slide 10

Slide 10 text

Решение 2: Kotlin-коллекции fun getFirstActualTimeIndex(times: List) = times.mapIndexed { idx, date -> Pair(idx, date) } .filter { it.second >= Date() } .map { it.first } .firstOrNull() ?: -1 10

Slide 11

Slide 11 text

Kotlin-коллекции — это мощь! fun getFirstActualTimeIndex(times: List) = times.indexOfFirst { it >= Date() } 11

Slide 12

Slide 12 text

Причем здесь Rx? 12

Slide 13

Slide 13 text

У всего этого есть что-то общее... ● это паттерн? ● похоже на “стримы” из Java 8 ● что это дает? 13

Slide 14

Slide 14 text

14

Slide 15

Slide 15 text

Rx и Kotlin - быстрое погружение ● те, кто владеет Rx, уже использует монады 15 ● Observable - монада с определенным частным поведением ● коллекции в Kotlin - тоже

Slide 16

Slide 16 text

Монада? ● в общем случае, контейнер 16 ● можно класть значение ● безопасно выполнять некоторые операции

Slide 17

Slide 17 text

Реализация ● поместить значение? // create Kotlin-list val ls = listOf(1, 2, 3) 17 // put the value Observable.just(1); // using various from-methods List ls = new ArrayList<>(); Observable.fromIterable(ls);

Slide 18

Slide 18 text

Реализация ● применить операцию? 18 val ls = listOf(1, 2, 3) println(ls) // [1, 2, 3]

Slide 19

Slide 19 text

Реализация ● применить операцию? 19

Slide 20

Slide 20 text

Реализация ● применить операцию? 20 listOf(1, 2, 3) .map { it + 3 } .map { "$it-" } .forEach { print(it) } // 4-5-6-

Slide 21

Slide 21 text

Реализация ● применить операцию? 21 listOf(1, 2, 3) .map { listOf(it, it + 3) } .map { "$it-" } .forEach { print(it) } // [1, 4]-[2, 5]-[3, 6]-

Slide 22

Slide 22 text

Реализация ● применить операцию? 22 listOf(1, 2, 3) .flatMap { listOf(it, it + 3) } .map { "$it-" } .forEach { print(it) } // 1-4-2-5-3-6-

Slide 23

Slide 23 text

Реализация ● связывание? 23 flatMap = flatten + map

Slide 24

Slide 24 text

Реализация — резюмируя ● поместить значение ● применить операцию ● связывание ● кон-р, фабр. методы ● map ● flatMap 24

Slide 25

Slide 25 text

Простейший пример Монада Option (Scala), она же Maybe (Haskell) 25

Slide 26

Slide 26 text

Null Safety в Kotlin data class Person( val firstName: String?, val lastName: String?) 26

Slide 27

Slide 27 text

Null Safety в Kotlin data class Person( val firstName: String?, val lastName: String?) data class Employee( val person: Person?, val department: String) 27

Slide 28

Slide 28 text

Null Safety в Kotlin data class Person( val firstName: String?, val lastName: String?) val ivanov: Employee? = Employee( Person("Ivan", "Ivanov"), "it") data class Employee( val person: Person?, val department: String) 28

Slide 29

Slide 29 text

Null Safety в Kotlin data class Person( val firstName: String?, val lastName: String?) val ivanov: Employee? = Employee( Person("Ivan", "Ivanov"), "it") val firstCharInFirstName: Char? = data class Employee( val person: Person?, val department: String) 29 ivanov?. person?.firstName?.first()

Slide 30

Slide 30 text

Решение с помощью Option val firstCharInFirstName: Char? = ivanIvanov .flatMap { it.person } .flatMap { it.firstName } .map(String::firstOrNull) .unwrap() 30 ivanIvanov ?.person ?.firstName ?.first()

Slide 31

Slide 31 text

Разворачивание Option-значений 31

Slide 32

Slide 32 text

Rx-chains // api fun getNews(date: Date): Observable 32

Slide 33

Slide 33 text

Rx-chains // api fun getNews(date: Date): Observable // mapper fun parseEntities(response: NewsResponse): List 33

Slide 34

Slide 34 text

Rx-chains // api fun getNews(date: Date): Observable // mapper fun parseEntities(response: NewsResponse): List // db fun saveNews(List): Observable 34

Slide 35

Slide 35 text

Rx-chains fun fetchNews(date: Date): Observable fun parseEntities(response: NewsResponse): List fun saveNews(List): Observable 35 fun getNews(date: Date) .map(mapper::parseEntities) .flatMap(db::saveNews) .toCompletable() = api.fetchNews(date)

Slide 36

Slide 36 text

Больше монад! ● Future в Scala кейс тот же, что с Rx-chains 36 ● Try связать операции, бросающие Exception’ы ● Either получить одно или другое значение

Slide 37

Slide 37 text

Монада — теоретический подход 37

Slide 38

Slide 38 text

Как появилась монада? 38

Slide 39

Slide 39 text

Как появилась монада? 39

Slide 40

Slide 40 text

Поведение и роли ● Type classes Monad, Functor, Applicative, etc ● Data types Option, Either, Try, etc 40

Slide 41

Slide 41 text

В контексте Kotlin ● не писать Java-style код ● использовать все возможности Kotlin ● решать задачи на другом уровне ● интересные решения на ФЯП 41

Slide 42

Slide 42 text

Так ли все безоблачно? ● увеличивает порог входа ● углубление в теорию ● “оверинжиниринг” простых задач 42

Slide 43

Slide 43 text

Решение проблем! ● код читается лучше ● последовательность шагов ● стейт внутри монады 43

Slide 44

Slide 44 text

Open-source Kotlin ● Kategory github.com/kategory/kategory ● funKTionale github.com/MarioAriasC/funKTionale Java 8+ ● Vavr, Functional Java, etc 44

Slide 45

Slide 45 text

Спасибо за внимание! 45 @kbiakov