Upgrade to Pro — share decks privately, control downloads, hide ads and more …

О монадах по-человечески — Кирилл Бяков (Туту.ру)

AvitoTech
November 25, 2017

О монадах по-человечески — Кирилл Бяков (Туту.ру)

Кирилл Бяков расскажет о монадах. В докладе речь пойдёт о проблематике, назначении, области использования, примерах известных монад и чек-листе того, что необходимо, чтобы использовать их в работе с Kotlin. И конечно, тех минусах, которые надо учесть при работе с монадами.

Kotlin Night Moscow
25/11/2017

AvitoTech

November 25, 2017
Tweet

More Decks by AvitoTech

Other Decks in Technology

Transcript

  1. 2

  2. 3

  3. Проблема 1: слабая читаемость static int getFirstActualTimeIndex(List<Date> 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
  4. Проблема 2: неясен момент завершения static int getFirstActualTimeIndex(List<Date> 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
  5. Imperative vs Declarative • переход от императивной парадигмы к декларативной

    позволяет писать более безопасный и предсказуемый код 8 • алгоритм состоит из последовательных шагов: не то, как ты это делаешь, а что именно • такой код легче читается и более краток
  6. Решение 1: в лоб, используя Rx static int getFirstActualTimeIndex(List<Date> 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
  7. Решение 2: Kotlin-коллекции fun getFirstActualTimeIndex(times: List<Date>) = times.mapIndexed { idx,

    date -> Pair(idx, date) } .filter { it.second >= Date() } .map { it.first } .firstOrNull() ?: -1 10
  8. У всего этого есть что-то общее... • это паттерн? •

    похоже на “стримы” из Java 8 • что это дает? 13
  9. 14

  10. Rx и Kotlin - быстрое погружение • те, кто владеет

    Rx, уже использует монады 15 • Observable - монада с определенным частным поведением • коллекции в Kotlin - тоже
  11. Монада? • в общем случае, контейнер 16 • можно класть

    значение • безопасно выполнять некоторые операции
  12. Реализация • поместить значение? // create Kotlin-list val ls =

    listOf(1, 2, 3) 17 // put the value Observable.just(1); // using various from-methods List<String> ls = new ArrayList<>(); Observable.fromIterable(ls);
  13. Реализация • применить операцию? 20 listOf(1, 2, 3) .map {

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

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

    listOf(it, it + 3) } .map { "$it-" } .forEach { print(it) } // 1-4-2-5-3-6-
  16. Null Safety в Kotlin data class Person( val firstName: String?,

    val lastName: String?) data class Employee( val person: Person?, val department: String) 27
  17. 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
  18. 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()
  19. Решение с помощью Option val firstCharInFirstName: Char? = ivanIvanov .flatMap

    { it.person } .flatMap { it.firstName } .map(String::firstOrNull) .unwrap() 30 ivanIvanov ?.person ?.firstName ?.first()
  20. Rx-chains // api fun getNews(date: Date): Observable<NewsResponse> // mapper fun

    parseEntities(response: NewsResponse): List<NewsEntity> 33
  21. Rx-chains // api fun getNews(date: Date): Observable<NewsResponse> // mapper fun

    parseEntities(response: NewsResponse): List<NewsEntity> // db fun saveNews(List<NewsEntity>): Observable<Boolean> 34
  22. Rx-chains fun fetchNews(date: Date): Observable<NewsResponse> fun parseEntities(response: NewsResponse): List<NewsEntity> fun

    saveNews(List<NewsEntity>): Observable<Boolean> 35 fun getNews(date: Date) .map(mapper::parseEntities) .flatMap(db::saveNews) .toCompletable() = api.fetchNews(date)
  23. Больше монад! • Future в Scala кейс тот же, что

    с Rx-chains 36 • Try<Something, Exception> связать операции, бросающие Exception’ы • Either<Left, Right> получить одно или другое значение
  24. В контексте Kotlin • не писать Java-style код • использовать

    все возможности Kotlin • решать задачи на другом уровне • интересные решения на ФЯП 41
  25. Так ли все безоблачно? • увеличивает порог входа • углубление

    в теорию • “оверинжиниринг” простых задач 42