1, 
2, 
3, 
4, 
5, 
6, 
7, 
8, 
9, 
10Читатели спрашивают, а на хрена нам, практикам, сдались эти ваши монады? Мы и без монад хорошо зарабатываем.
Тут можно спросить собеседников, а нужна ли им также проза? Зачем им проза, они и без прозы хорошо могут обсуждать вопросы, например, у кого какая зарплата или почём хонда у дилеров. А что они сами употребляют прозу, обсуждая эти вопросы, то ещё Мольер писал в 17-м веке, но кто нынче читает Мольера - он ни в жж, ни в твиттер не пишет, так чо.
Итак, вы можете писать что угодно на чём угодно, в смысле программирования, и монады у вас там будут независимо от того, в курсе вы или нет. Если вы в вашу функцию вставляете 
System.out.println("Mom, I'm in a function!"), то это у вас монада. Если вы вставляете 
String myDrive = new File(".").getAbsolutePath().split(":")[0], то это тоже монада. Если у вас в коде 
User user = DaoFactoryManager.getUserDaoFactory().getUserDao().getUserByUserId(userId); if (user != null) ...
 то это тоже монада, даже две.
Так что можно уйти в несознанку, прожить долго и счастливо и умереть дураком, и это, конечно, вариант, но не для всех. Некоторым просто любопытно.
Итак, проблемы.
Скажем, какой-нибудь метод 
livejournal.getFriends(userid: String): Option[Set[String]] - он возвращает или 
Some[Set[String]], или 
None когда жж в дауне, т.е. довольно часто.
В нашем коде мы можем не мудрствовать особо-то, а прям так и писать:
  livejournal.getFriends("ivan_gandhi") match {
    case None          => err.println("ну вот, опять Носик сломал код")
    case Some(friends) => { println("Это всё мои друзья:"); for (friend <- friends) println(" - " + friend) }
  }
Мы тут употребили три монады как минимум (на самом деле пять), но ощутили только одну. Это ничего.
А вот представьте теперь, что нам за каким-то хреном понадобилось составить список fof - friends-of-friends, Друзья Друзей. Ну и как мы это будем делать?
Если бы 
livejournal никогда не ошибался, а всегда бы возвращал 
Set[String], то мы ж могли бы выразить это наше действие одним циклом:
for (f   <- livejournal.getFriends("ivan_gandhi");
     fof <- livejournal.getFriends(f)
    ) println(" - " + fof)
или, эквивалентно и идиоматично, в одну строчку:
livejournal.getFriends("ivan_gandhi").flatMap(f => livejournal.getFriends(f)).foreach(x => println(" - " + x))
На то она и монада, что все эти действия происходят автоматически. И кстати, я не поминал раньше 
flatMap.
flatMap - это 
map за которым следует 
flatten - сначала мы применяем 
map, получая, в нашем случае, 
Set[Set[String]], а потом уже сплющиваем 
Set[Set[String]] → Set[String]. Сплющивание монады 
Set вещь не совсем тривиальная; могут попадаться дубликаты, их игнорируем.
Ну хорошо, а что же делать в нашем случае? Теоретически, в качестве результата мы получаем 
Option[Set[Option[Set[String]]]]. Мы можем получить ошибку при выборке списка наших друзей, и при выборке списка друзей любого из наших друзей, и неоднократно. Что можно предпринять? Можно прописать решение руками, например:
for (fOpt   <- livejournal.getFriends("ivan_gandhi");
     f      <- fOpt;
     fofOpt <- livejournal.getFriends(f);
     fof    <- fofOpt
    ) println(" - " + fof)
Такое решение годится для данного конкретного случая. Но не для общего случая. Представьте такое:
for (stockOpt   <- etrade.getPortfolio("vpatryshev", "password1");
     stock      <- stockOpt;
     batchOpt   <- etrade.getTrades("vpatryshev", "password1", stock);
     batch      <- batch
    ) println(stock + ": " + batch.size + "@" + batch.purchasePrice)
Этот код распечатывает историю покупок акций; ну и представьте себе, что вы точно знаете, что вчера купили BIDU, а её в распечатке нету. Ну потому что проигнорировали. Так нельзя; надо было сразу же бросать какое-нибудь исключение, сигнализировать, что ой, не все данные собраны.
То есть смотрите - если у нас есть 
Set[Set[T]], то мы это можем сплющить. А если 
Set[Option[Set[Option[T]]]], то неочевидно. Если бы мы могли это преобразовать в 
Set[Set[Option[Option[T]]]], то можно было бы отдельно плющить 
Set[Set[...]] и 
Option[Option[T]]. Но проблема в том, что в общем виде такого преобразования 
не существует. 
Монады не коммутируют. Не существует, в общем виде, преобразования 
M[N[x]] → N[M[x]]. Но, разумеется, в каждом конкретном случае можно какое-нибудь такое преобразование выдумать. Такие преобразования называются monad transformers по-английски; как они называются по-русски, я понятия не имею; не трансформеры же, и не трансформаторы же. Буду употреблять слово "преобразование" пока меня не поправят. Если б алгебраисты знали, какой тут катаклизм, они б подсказали - да коммутатор это, коммутатор. Но алгебраисты обычно такой фигнёй не занимаются.
Посмотрим, что можно сделать в случае 
Option. Нам нужно преобразование 
optionT: Option[M[T]] → M[Option[T]], независимо от природы 
M. Вот стандартное решение:
def optionT[M[_], T](optionalmt: Option[M[T]]) = optionalmt match {
  case None => M.unit(None)                // засунули None внутрь M, получив M[Option[T]]
  case Some(mt) => mt.map(t => Some(t))    // засунули Some() внутрь M, получив M[Option[T]] 
}
Хотя такое преобразование и не годится для примера с акциями, оно годится для примера с друзьями друзей. В примерах выше оно не используется, однако. На самом деле, в скальном цикле происходит вот что: и 
Set[T], и 
Option[T] наследуют от 
Iterable[T]; поэтому мы фактически сплющиваем 
Iterable[Iterable[Iterable[Iterable[T]]]], получая в конце концов 
Iterable[T]; дальше его можно вручную превратить в 
Set[T].
Аналогично можно определить преобразование 
List[M[T]] → M[List[T]]. Но не в общем виде. Поэтому в скале и в хаскеле существуют чуть ли не библиотеки преобразований; а т.к. решение в общем случае довольно произвольно, то нельзя сказать, что это единственно правильные преобразования.
Но в целом же грустный вывод такой, что композиция монад - не обязательно монада. Если не коммутируют - то не монада. А не коммутируют они... ну смотрите, в кубике Рубика повернёте верхнюю грань по часовой стрелке, переднюю по часовой стрелке, потом верхнюю против часовой стрелки, переднюю против часовой стрелки. Это, очевидно, не тождественное преобразование - не всякая группа коммутативна.
Вот этот факт, некоммутирование монад, по-моему, является одной из причин, почему программирование не является тривиальным занятием.
На эту тему много интересного можно почитать у 
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif) akuklev
akukleva, у 
Дебасиша, у Тони Морриса (
Monads do not compose), ну или, если ваш уровень хаскеля достаточен, можно прочитать 18-ю главу rwh, или 
вот это.
Итак, мы не можем произвольно строить монады из данных нам природой монад; но в жизни-то мы хотим соединять преобразования данных так, как нам надо; и, следовательно, надо искать какую-то не то чтобы замену монадам, а послабление. Можем же мы обойтись без чего-то?
Это послабление в компьютерной науке называется аппликативным функтором. В следующей части мы постепенно перекатимся от монад к аппликативным функторам. В компьютерной науке есть поверие, что всякая монада является аппликативным функтором. Это не так, но это ещё более другая тема.