Композиция IO
Выстраивайте эффекты в последовательность
«Композиция IO» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Выстраивание в последовательность с flatMap
Поскольку IO является монадой, вы компоновываете эффекты с помощью flatMap. Каждый шаг выполняется по порядку, а следующий шаг может использовать результат предыдущего.
import cats.effect.IO
val program: IO[Unit] =
IO("Alice").flatMap(name => IO.println(s"Hello, $name"))for-композитор
Конструкция for преобразуется в flatMap/map и читается как императивный сценарий, сохраняя при этом чистоту.
import cats.effect.IO
val prog: IO[Unit] = for {
_ <- IO.println("What is your name?")
name <- IO("Bob")
_ <- IO.println(s"Hi $name")
} yield ()Порядок сохраняется
Эффекты внутри конструкции for выполняются сверху вниз при запуске программы. Структура кода отражает порядок выполнения.
Объединение независимых эффектов
Если два эффекта не зависят друг от друга, используйте mapN или (a, b).tupled, чтобы объединить их. По умолчанию они всё равно выполняются последовательно, но такой код выражает их независимость.
import cats.effect.IO
import cats.syntax.apply._
val combined: IO[Int] = (IO(2), IO(3)).mapN(_ + _)Параллельный запуск эффектов
Используйте parMapN (из cats.syntax.parallel), чтобы одновременно запускать независимые эффекты в отдельных волокнах и объединять их результаты.
import cats.effect.IO
import cats.syntax.parallel._
val par: IO[Int] = (IO(2), IO(3)).parMapN(_ + _)Отбрасывание результатов
Используйте *>, чтобы выполнить эффект и сохранить второй результат, или <*, чтобы сохранить первый. void полностью отбрасывает результат, выдавая IO[Unit].
import cats.effect.IO
val r1: IO[Int] = IO.println("log") *> IO(42)
val r2: IO[Unit] = IO(99).voidПовторение эффектов
replicateA(n) выполняет эффект n раз и собирает результаты в список. foreverM повторяет его бесконечно.
import cats.effect.IO
val three: IO[List[Unit]] = IO.println("tick").replicateA(3)Обход списка
Преобразуйте List[A] в эффект над List[B] с помощью traverse. Каждый элемент создаёт IO, а результаты собираются вместе.
import cats.effect.IO
import cats.syntax.traverse._
val names = List("a", "b", "c")
val prog: IO[List[Unit]] = names.traverse(n => IO.println(n))parTraverse
parTraverse — параллельная версия traverse: эффект каждого элемента выполняется в собственном волокне. Это особенно удобно для одновременных операций ввода-вывода, например получения множества URL.
import cats.effect.IO
import cats.syntax.parallel._
val ids = List(1, 2, 3)
val prog: IO[List[Int]] = ids.parTraverse(id => IO(id * 10))Скомпонованная программа
Эта программа считывает значение, удваивает его и выводит результат — всё это скомпоновано из небольших шагов IO в одном описании.
import cats.effect.{IO, IOApp}
object Doubler extends IOApp.Simple {
def run: IO[Unit] = for {
n <- IO(21)
d = n * 2
_ <- IO.println(s"Doubled: $d")
} yield ()
}Последовательность в обычной Scala
Для сравнения приведём последовательный вывод в консоль на обычной Scala — нетерпеливый и нечистый, в отличие от рассмотренной выше версии с отложенным IO.
object Main {
def main(args: Array[String]): Unit = {
val n = 21
val d = n * 2
println(s"Doubled: $d")
}
}Быстрая проверка
Какой метод одновременно выполняет два независимых эффекта и объединяет их результаты?
Итоги
Вы компоновывали программы IO с помощью:
flatMapиforдля выстраивания в последовательностьmapN/parMapNдля независимых эффектов*>,<*,voidдля объединения и отбрасыванияtraverse/parTraverseдля коллекций
Далее: обработка ошибок внутри IO.
Часто задаваемые вопросы
Урок «Композиция IO» бесплатный?
Да — полный текст урока «Композиция IO» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Чему я научусь в уроке «Композиция IO»?
Выстраивайте эффекты в последовательность Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?
Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Композиция IO»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?
Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Классы типов Cats
- Монада IO
- Композиция IO
- Обработка ошибок в IO