Комментарии 9
Ехал IO через ZIO
Видит IO: в ZIO map
Тогдашний род учения страшно расходился с образом жизни: эти схоластические, грамматические, реторические и логические тонкости решительно не прикасались ко времени, никогда не применялись и не повторялись в жизни. Учившиеся им ни к чему не могли привязать своих познаний, хотя бы даже менее схоластических. Самые тогдашние ученые более других были невежды, потому что вовсе были удалены от опыта.
Н. В. Гоголь
Между фундаментальной теорией и программированием действительно пропасть. В интернете полно материалов о том, КАК надо пользоваться всеми инструментами, что предлагает математика. И гораздо меньше популярных изложений теории.
Считаю ценной любую попытку преодолеть эту пропасть, популярно обосновать необходимость инструментов, предлагаемых наукой.
Я, действительно "невежда", но не потому что "математик, удалённый от опыта". Наоборот, я программист, которому часто недостаёт фундаментального математического образования. Тем не менее, стараюсь восполнять эти пробелы самому и публикую статьи в надежде, что это поможет и другим.
"Я вот тоже Брокгауза и Ефрона читал. Два тома прочел. Читаешь, читаешь - слова легкие: Мечислав, Богоуслав и убей бог не помню какой-кто. Книжку закроешь - все вылетело.Помню только - Мандриан! Какой Мандриан? - нет там никакого Мандриана. Там с левой стороны - два Бронецких: один - брат Адриан, другой - Мариан, а у меня - Мандриан!" (c)
Пожалейте мой мозг
TL;DR
Монада — это не обёртка, а способ композиции вычислений с эффектами
Представьте, что у вас есть функции вида A → F[B], где F — не просто контейнер, а контекст: ошибка, состояние, асинхронность, недетерминированность и т.п. Просто скомбинировать такие функции нельзя — результат «вкладывается»: F[F[C]]. Чтобы получить F[C], нужна операция разматрёшивания (flatten).
Но одной flatten мало. Чтобы композиция была предсказуемой, она должна удовлетворять законам:
Ассоциативность:
(f >=> g) >=> hдолжно быть тем же, что иf >=> (g >=> h).
Это накладывает условие на то, какflattenвзаимодействует с самим собой.Нейтральный элемент:
Существует операцияpure : A → F[A], которая «упаковывает» значение без эффекта.
Она должна быть согласована сflatten:pure >=> f = f = f >=> pure.Lift, который даёт доступ к map, чтобы применить функцию внутри контекста
Эти требования — и есть определение монады. Формально: монада — это эндофунктор с двумя естественными преобразованиями (pure и flatten), удовлетворяющими этим законам.
Почему это важно?
Монады позволяют явно выразить порядок и зависимость эффектов.
flatMap(или оператор Клейсли>=>) — для последовательных вычислений, где следующий шаг зависит от результата предыдущего.Аппликативный стиль (
map2,zip) — для независимых эффектов, которые можно выполнять параллельно или в любом порядке.
Это не просто «синтаксический сахар». Это архитектурный выбор: выносить побочные эффекты из логики и делать их частью типа.
Но монады не композируются
Если F и G — монады, это не гарантирует, что G[F[_]] тоже монада.
Чтобы скомбинировать их, нужен дистрибутивный закон — естественное преобразование видаF[G[A]] → G[F[A]],
согласованное с обеими монадными структурами.
Такие законы существуют не всегда. Поэтому на практике используют монадные трансформеры (OptionT, StateT и т.д.) — ручные конструкции, вшивающие один эффект в другой.
Вывод
Монада — это не «магия Haskell», а алгебраическая структура для композиции вычислений с контекстом.
Она отвечает на вопрос: «Как надёжно соединить шаги, каждый из которых может что-то сделать помимо возврата значения?»
И в этом — её сила: не в сокрытии сложности, а в явном управлении ею
Монада нужна, чтобы предсказуемо компоновать вычисления с эффектами — ошибками, состоянием, асинхронностью и т.п.
Она даёт:
Порядок: эффекты происходят в нужной последовательности.
Контекст: тип сам говорит, что может пойти не так или откуда берутся данные.
Законы: рефакторинг не ломает поведение — благодаря ассоциативности и нейтральному элементу.
Короче: монада — это алгебра для управления побочными эффектами, а не просто «обёртка».
Снова спасибо за конспект - кому-то может пригодится.
Вот только у меня нигде не говорится, что "монада - это обёртка". Наоборот, я делаю акцент на том, что это возможность предсказуемого "разматрёшивания обёртки". А уж для чего она используется в программировании и так уже много где написано. Да и в "магический Хаскель" монада попала точно также как и в любые другие языки программирования - из теории категорий.
Аппликативный стиль (
map2,zip) — для независимых эффектов, которые можно выполнять параллельно или в любом порядке.
вроде как надо разграничить, что вообще-то из аппликативного стиля не следует "автоматическая" параллельность)
в Haskell, в Catsлевонаправленное последовательное исполнение по умолчанию, если правильно помню. Там даже отдельная функция есть для параллельности - parMapN
вообще оцените метафору вчера читал эту статью и суши хавал:
Applicative - это когда ты заказываешь несколько роллов у конкретного ресторана, который спрашивает как именно их подать 💀💀💀
В языках топ 10-15 монад нет, как я понял?
Но концепция railway oriented programming с упрощениями реализуется
Хотя, на практике такого хватает для railway
// Domain error
enum MyError {
Database(sqlx::Error),
Network(reqwest::Error),
}
impl From<sqlx::Error> for MyError {
fn from(e: sqlx::Error) -> Self {
Self::Database(e)
}
}
// Бизнес-логика чистая
fn business_logic() -> Result<T, MyError> {
let data = db_query()?; // auto-convert sqlx error -> MyError
Ok(data)
}Если в языке есть статическая типизация и обобщённые типы, то там наверняка есть и что-то похожее на монады. Собственно, обобщённые типы обычно и добавляют в язык именно для предсказуемой композиции эффективных вычислений с помощью монад. Например, монадные возможности представлены у `Task`, `IEnumerable`, `Nullable` в C#. В Java есть Flux/Mono в специализированной библиотеке.
Абстрактные монадные возможности предоставляются обобщённым типам посредством типов высокого рода (`Monad[_[_]]`) - вот они-то в популярных языках встречаются редко.

Категории типов. Часть 4. Монады