Either: суть, застосування та принцип роботи

Автор: IT Sectr Опубліковано: 2026-05-26 Час читання: 8 хв

Either — функціональний тип, який представляє значення одного з двох можливих варіантів: лівий (Left) для помилки і правий (Right) для успіху. На відміну від винятків, Either робить обробку помилок явною на рівні типів і не потребує блоків try-catch. За даними Arrow, 2026, Either широко застосовується в Kotlin-проєктах для композиції операцій, які можуть завершитися збоєм, без побічних ефектів.

Головне

  • Either — алгебраїчний тип даних для представлення двох взаємовиключних варіантів: Left (помилка) і Right (успіх).
  • Left традиційно містить інформацію про помилку, Right — коректне значення.
  • Явна типізація — Either змушує обробляти обидва варіанти на етапі компіляції, виключаючи несподівані збої.
  • Композиція — Either підтримує map, flatMap і fold для ланцюжків перетворень без вкладених перевірок.
  • Відмінність від Result — Either може зберігати довільний тип помилки, а не тільки Error або Throwable.

Що таке Either?

Either — це алгебраїчний тип даних, запозичений із функціонального програмування, який представляє рівно одне з двох можливих значень. У контексті обробки помилок прийнято погодження: лівий тип (Left) містить опис проблеми, а правий (Right) — успішний результат.

Концепція Either походить із мови Haskell і категорії типів Either a b, де a — тип лівого значення, b — правого. У мобільній розробці Either набув поширення завдяки бібліотеці Arrow для Kotlin і функціональним підходам у Swift.

Ключова перевага Either перед винятками — відсутність прихованих шляхів виконання. Функція, що повертає Either, явно заявляє у своїй сигнатурі, що може завершитися помилкою. Компілятор контролює, чи оброблені обидва варіанти.

На відміну від викидання винятків, Either зберігає прозорість потоку даних. Виклик функції, що повертає Either, не потребує try-catch на стороні викликаючого коду — достатньо pattern-matching або fold. Це особливо важливо в архітектурах з реактивним підходом, де кожне джерело даних повертає Either, а ланцюжок трансформацій будується через map і flatMap.

Як працює Either: структура Left і Right

Either складається з двох підтипів: Left і Right. Екземпляр Either може бути тільки одним із них у кожен момент часу. Типова сигнатура в Kotlin виглядає як Either<E, A>, де E — тип помилки, A — тип успішного значення.

Тип Left: контейнер помилки

Left представляє випадок збою. На відміну від винятків, Left не перериває потік виконання — він просто повертає значення, яке потрібно обробити. Тип помилки може бути будь-яким: String, Int, кастомний sealed class або доменна модель.

Тип Right: контейнер успіху

Right містить коректний результат операції. Назва відображає «правильність» — за погодженням Right означає успіх. Саме на Right застосовуються трансформації map і flatMap, що дозволяє будувати ланцюжки обчислень без перевірки кожного кроку.

Композиція Either через flatMap

flatMap — основний механізм композиції Either. Якщо поточне значення — Right, flatMap застосовує передану функцію і повертає новий Either. Якщо Left — flatMap пропускає перетворення і передає помилку далі. Ця поведінка називається short-circuit evaluation.

Крім flatMap, Either підтримує mapLeft для трансформації помилки, fold для обробки обох варіантів в одному місці та getOrElse для вилучення значення зі значенням за замовчуванням. Ці функції покривають усі сценарії: від простого вилучення до складної композиції з асинхронними викликами в корутинах Kotlin або Combine у Swift.

kotlin
fun parseInt(input: String): Either<String, Int> =
    input.toIntOrNull()?.let { Right(it) }
    ?: Left("Не вдалося перетворити: $input")

fun divide(a: Int, b: Int): Either<String, Int> =
    if (b == 0) Left("Ділення на нуль")
    else Right(a / b)

val result = parseInt("10")
    .flatMap { divide(it, 2) }

Either у Kotlin: практичне застосування

В екосистемі Kotlin Either реалізовано в бібліотеці Arrow. Стандартна бібліотека Kotlin пропонує Result, але Either дає більше гнучкості: довільний тип помилки, композиція через flatMap і підтримка функціональних патернів.

Бібліотека Arrow і Either

Arrow — функціональна бібліотека для Kotlin, яка додає Either, Option, Validated та інші типи. Arrow.Either — sealed class із двома нащадками: ArrowCore.Left і ArrowCore.Right. Бібліотека також надає розширення для зручної роботи: .getOrElse(), .fold(), .mapLeft().

Приклад: Either із мережевим запитом

Розглянемо реальний сценарій — мережевий запит у Android застосунку з можливими помилками: відсутність мережі, помилка сервера, некоректна відповідь. Either дозволяє об'єднати всі варіанти в одному поверненому типі.

kotlin
sealed class NetworkError {
    data class NoConnection(val message: String): NetworkError()
    data class ServerError(val code: Int): NetworkError()
    data class ParseError(val detail: String): NetworkError()
}

suspend fun fetchUser(id: String): Either<NetworkError, User> {
    return try {
        val response = api.getUser(id)
        if (response.isSuccessful) {
            Right(response.body()!!)
        } else {
            Left(NetworkError.ServerError(response.code()))
        }
    } catch (e: IOException) {
        Left(NetworkError.NoConnection(e.message ?: ""))
    }
}

Either у Swift: відмінність від стандартного Result

У Swift починаючи з версії 5.0 з'явився вбудований Result тип, який концептуально схожий на Either, але має обмеження: помилка повинна відповідати протоколу Error, а успішне значення — одному типу. Either у Swift реалізується через enum із двома generic-параметрами.

Стандартний Result проти Either

Result<Success, Failure> — вбудований тип Swift, де Failure: Error. Either не накладає обмежень на тип помилки, що дозволяє зберігати String, кастомні структури або навіть кілька типів помилок через вкладені enum.

swift
enum Either<E, A> {
    case left(E)
    case right(A)

    func map<B>(_ transform: (A) -> B) -> Either<E, B> {
        switch self {
        case .left(let e): return .left(e)
        case .right(let a): return .right(transform(a))
        }
    }
}

let result: Either<String, Int> = .right(42)
let mapped = result.map { $0 * 2 }

Коли використовувати Either у мобільних застосунках

Either оптимальний для сценаріїв, де потрібна явна та типобезпечна обробка помилок без винятків. Розглянемо основні випадки застосування в мобільній розробці на Kotlin і Swift.

  • Мережеві запити — кожен запит може повернути помилку з'єднання, сервера або парсингу. Either збирає всі варіанти в один тип.
  • Валідація форм — Either із кастомним типом помилки зручно представляє результат перевірки полів введення: невалідний email або пароль.
  • Репозиторій даних — Either дозволяє об'єднати результат із різних джерел (кеш, БД, мережа) з єдиним типом помилки.
  • Інтерпретатор команд — якщо застосунок розбирає введення користувача або команди, Either дає типобезпечний спосіб повідомити про помилку.

Не варто використовувати Either для простих операцій без побічних ефектів — звичайне повернене значення надійніше та читається легше. Також Either надлишковий, коли збій — це виняткова ситуація, а не очікуваний сценарій.

Either також ефективний при роботі з корутинами в Kotlin. Функція, що повертає Either, може бути викликана всередині корутини з обробкою помилки через fold або mapLeft без блокування потоку. Це особливо корисно в Android-застосунках з архітектурою MVVM, де кожен репозиторій повертає Either, а ViewModel трансформує результат у UiState.

Типові помилки при роботі з Either

Розробники, які вперше знайомляться з Either, часто допускають схожі помилки. Розглянемо найпоширеніші та способи їх уникнути.

  • Ігнорування Left — виклик .getOrElse() зі значенням за замовчуванням без аналізу причини помилки позбавляє сенсу використання Either. Обробляйте помилку явно.
  • Глобальний тип помилки — використання String або Exception як спільного типу для всіх Either у проєкті знижує типобезпеку. Створюйте доменні sealed class.
  • Вкладені Either — повторний Either всередині Right (Either<E, Either<E, A>>) ускладнює читання. Використовуйте flatMap для вирівнювання.
  • Змішування з винятками — функція повертає Either, але всередині викидає виняток. Це суперечить ідеї явної обробки помилок.

Часті запитання

Чим Either відрізняється від Optional?

Optional представляє наявність або відсутність значення (Some/None), але не повідомляє причину відсутності. Either дає два конкретних типи — лівий для помилки і правий для успіху, що дозволяє передавати контекст збою.

Чи можна використовувати Either у Java?

У Java немає вбудованого Either, але бібліотеки Vavr і functionaljava надають реалізацію. В Android-розробці Either із Vavr — популярна альтернатива для функціонального стилю з лямбдами.

Коли краще використовувати sealed class замість Either?

Sealed class у Kotlin зручніший, коли варіантів більше двох або вони мають різну структуру. Для бінарного результату (помилка/успіх) Either компактніший і надає готові функціональні комбінатори.

Чи підтримує Either багатопотоковість?

Either імутабельний і потокобезпечний за замовчуванням. У Kotlin з корутинами Either чудово комбінується: flatMap працює всередині coroutine scope, а обробка помилок не потребує блокувань.

Чи варто використовувати Either для всіх функцій у проєкті?

Ні. Either доречний для операцій з очікуваними збоями (мережа, валідація, бізнес-логіка). Для простих геттерів і обчислень без побічних ефектів звичайний тип читається простіше та не додає зайвої складності.

Підсумки

  • Either — функціональний тип для представлення двох варіантів: Left (помилка) і Right (успіх), що робить обробку збоїв явною на рівні типів.
  • Left може містити довільний тип помилки — від String до доменного sealed class, на відміну від стандартного Result.
  • flatMap забезпечує композицію Either без вкладених перевірок: помилка автоматично проброшується через увесь ланцюжок.
  • Arrow — основна бібліотека Either для Kotlin із вбудованою підтримкою корутин і розширень.
  • Swift використовує вбудований Result, але Either реалізується через enum із двома generic-параметрами для повної гнучкості.
  • Застосовуйте Either для мережевих запитів, валідації форм і репозиторіїв — сценаріїв з очікуваними помилками.
  • Уникайте глобального типу помилки, ігнорування Left і вкладених Either — це знижує переваги типобезпеки.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також