Шаг 229.
Основы Kotlin.
Основы функционального программирования. Библиотека Arrow.kt

    На этом шаге мы дадим краткую характеристику этой библиотеке.

    В предыдущих шагах вы познакомились с инструментами функционального программирования, встроенными в стандартную библиотеку Kotlin, такими как map(), flatMap() и filter().

    Kotlin - "мультипарадигмальный" язык. Это означает, что он смешивает приемы объектно-ориентированного, императивного и функционального программирования. Если вы работали со строго функциональным языком, таким как Haskell, то знаете, что он предлагает гораздо более продвинутые приемы функционального программирования, чем Kotlin.

    Например, Haskell содержит тип Maybe - тип, который включает поддержку какого-то значения или ошибки. Это позволяет операциям, которые могли привести к сбою, возвращать результат этого типа. Использование типа Maybe позволяет сообщить об исключении (например, об ошибке парсинга числа), не возбуждая его. Благодаря этому отпадает необходимость использовать оператор try/catch.

    Обрабатывать исключения без реализации логики try/catch, очень удобно. Некоторые представляют try/catch как форму инструкции GOTO, которая часто делает код сложным для понимания и поддержки. Многие возможности функционального программирования, доступные в Haskell, можно добавить в Kotlin через специальные библиотеки вроде Arrow.kt (https://arrow-kt.io/).

    Например, библиотека Arrow.kt включает подобие типа Maybe из Haskell с именем Either. Использование Either позволяет выразить операцию, которая может закончиться сбоем, не прибегая к исключениям и не требуя использовать оператор try/catch.

    В качестве примера рассмотрим функцию, которая преобразует ввод пользователя из строки в Int. Если пользователь введет допустимое число, оно будет преобразовано в значение Int, в противном случае функция выведет сообщение об ошибке.

    Использование Either приводит к следующей логике:

fun parse(s: String): Either<NumberFormatException, Int> = 
  if (s.matches(Regex("-?[0-9]+"))) {
    Either.Right(s.toInt())
  } else {
    Either.Left(NumberFormatException("$s is not a valid integer."))
  }
val x = parse("123")

val value = when(x) {
  is Either.Left -> when (x.a) {
    is NumberFormatException -> "Not a number!" 
    else -> "Unknown error"
  }
  is Either.Right -> "Number that was parsed: ${x.b}"
}

    Никаких исключений, никаких блоков try/catch - простая и понятная логика.

    На следующем шаге мы рассмотрим несколько заданий для самостоятельного решения.




Предыдущий шаг Содержание Следующий шаг