При использовании языка Go чувствуется нехватка хорошей библиотеки для работы с потоками данных. Имеющиеся библиотеки в основном написаны во времена до дженериков и имеют не очень удобный интерфейс. С выходом Go 1.18 появилась возможность реализовать библиотеку потоковой обработки данных goio, вдохновлённую превосходными Scala-библиотеками cats-effect и fs2. При обработке данных, объём которых превышает объём памяти вычислительного узла, необходимо использовать технологии потоковой обработки данных. При этом данные загружаются в память по частям, выполняется их обработка, а затем данные выгружаются из памяти. Для написания таких программ необходимо каким-либо образом решить ряд вопросов: обработка ошибок; представление конечных автоматов, реализующих отдельные этапы обработки данных; композиция конечных автоматов; использование нескольких ядер для параллельной обработки данных. От того, каким образом эти вопросы решены, зависит надёжность получающейся системы, читабельность кода, производительность. На мой вгляд, наиболее интересное решение предлагают Scala-библиотеки cats-effect и fs2. Многие функции не являются "тотальными". То есть они не всегда возвращают осмысленное значение. В языке Go принято представлять такие частичные функции с помощью возврата пары - значения функции и ошибки: При этом вызывающая сторона должна сразу проверить наличие ошибки: Такой способ представления ошибок создаёт неудобства при композиции нескольких вычислений. Принятым в функциональном программировании способом представления вычислений, которые могут завершиться неудачей, является IO[A]. IO[A] - объект, представляющий вычисление, которое в случае успеха возвращает значение типа A. (Это, несколько упрощённое представление IO, позволяет сфокусироваться на аспекте, связанном с обработкой ошибок.) В рассматриваемой библиотеке goio этот тип реализован. Например, вышеприведённая функция f может быть непосредственно "завёрнута" в IO[A]: (Также имеется целый набор удобных способов заворачивания вычислений в IO[A] - Lift, Fail, Delay.) Чтобы выполнить вычисление IO[A], используется метод UnsafeRunSync: операции создания IO и выполнения почти эквивалентны непосредственному вызову f. Отличие заключается в том, что при возникновении panic , производится восстановление (recover) в error. Какие возможности предоставляет тип IO[A]? Главная возможность - композиция вычислений. Выполнить одно вычисление, результат подставить в другое, и всё вместе представить как одно вычисление. Такая операция в библиотеке goio носит название FlatMap (также известна как bind): Предусмотрены и другие привычные комбинаторы - Map, AndThen, Sequence... Если IO[A] представляет собой однократное вычисление,то Stream[A] представляет потенциально бесконечный поток элементов A. Выполняя некоторое действие, можно последовательно получить все элементы из потока. Создать поток можно, например, из массива данных: Или можно создать бесконечный поток с использованием генератора: Также имеются и другие способы создания потоков - Empty, Lift, Repeat, Eval.  Обработка потока осуществляется конечным автоматом, имеющим вход и выход. Простейший случай - вход преобразуется в выход без внутреннего состояний. Такое преобразование осуществляется комбинатором Map: Универсальный механизм, позволяющий представить произвольный конечный автомат с состоянием - StateFlatMapWithFinish (см. пример в тестах). Имеются и другие комбинаторы - Filter, Flatten, AndThen, Take, Drop,... Чтобы выполнить все вычисления и получить результат обработки потока, используются финальные операции -  DrainAll, ToSlice, Collect,... В библиотеке также реализованы простые средства для работы с текстовыми файлами или http-запросами - ReadLines, WriteLines. Асинхронная операция выполняется вне текущего потока выполнения. То есть её можно запустить, передав в качестве аргумента callback, и продолжить работу текущего потока: Когда асинхронная операция завершится, она должна вызвать переданный callback. (Если callback не вызывается, то получится операция Never.) Текущий поток, после того, как выполнит свою оставшуюся работу, в какой-то момент может захотеть дождаться (Join) результата асинхронной операции. При этом текущий поток блокируется до получения результата (или ошибки). Для представления такой семантики параллельного исполнения используется Fiber[A] - вычисление, запускаемое в отдельной горутине, результат которой мы можем получить с помощью Join. Для создания Fiber используется функция Start(IO[A]) Fiber[A]. Для создания сразу большого числа параллельных вычислений используются комбинаторы Parallel и ConcurrentlyFirst. Одним из аспектов корректной обработки ошибок является освобождение ресурсов по окончании операций независимо от того, произошла ошибка или нет. Для представления таких ресурсов используется тип Resource[A]. Ресурсами могут быть соединения с базой данных, файлы, каналы... Основная операция, предусмотренная для ресурса - Use, позволяющая в ограниченном конексте получить доступ к экземпляру ресурса. При выходе за границы контекста производится автоматическое закрытие ресурса. Пример работы с ресурсами. Для организации межпоточного взаимодействия в языке Go предусмотрены каналы. Для корректной работы с каналами в библиотеке goio предусмотренна поддержка на всех уровнях. В пакете io : открытие/закрытие канала, отправка и чтение данных. В пакете stream: отправка потока данных в канал, формирование потока данных из канала, использование внешней системы, подключенной посредством входного и выходного каналов. В пакете resource: представление канала в виде ресурса - UnbufferedChannel[A any]() Resource[chan A].  Без привычных операций Map, FlatMap, Filter, ... работа с массивами не очень удобна. В библиотеке goio содержатся эти операции, реализованные с использованием generics. Библиотека goio содержит удобный набор инструментов для написания надёжных и корректных программ, осуществляющих потоковую обработку данных. Реализованы: представление вычислений, которые могут возвращать ошибки, и комбинация таких вычислений; представление абстрактных потоков данных; представление конечных автоматов, реализующих отдельные этапы обработки данных; композиция цепочки конечных автоматов, выполняющих операции над потоками данных; параллельная обработка данных; взаимодействие с другими частями программ, реализованными с использованием каналов Go. Библиотека доступна по лицензии MIT. PR приветствуются. Scala архитектор