Я понимаю (я думаю), что цель монад - «обернуть» побочные эффекты так, чтобы они были изолированы от остальной части программы.
Это на самом деле немного более тонко, чем это. Монады позволяют нам моделировать последовательность в очень общем виде. Часто, когда вы разговариваете с экспертом по предметной области, вы обнаруживаете, что он говорит что-то вроде: «сначала мы пробуем X. Затем мы пробуем Y, а если это не сработает, то мы пробуем Z». Когда вы реализуете что-то подобное на обычном языке, вы обнаруживаете, что оно не подходит, поэтому вам нужно написать много дополнительного кода, чтобы охватить то, что эксперт по домену имел в виду под словом «тогда».
В Haskell вы можете реализовать это как монаду с переводом «затем» в оператор связывания. Так, например, я однажды написал программу, в которой элемент должен быть назначен из пулов в соответствии с определенными правилами. Для случая 1 вы взяли его из пула X. Если он был пустым, то вы перешли к пулу Y. Для случая 2 вы должны были взять его прямо из пула Y. И так для дюжины или около того случаев, включая некоторые, где вы брали наименее недавно использованный из пула X или Y. Я специально для этой работы написал специальную монаду, чтобы написать:
case c of
1: do {try poolX; try poolY}
2: try poolY
3: try $ lru [poolX, poolY]
Это сработало очень хорошо.
Конечно, это включает в себя обычные модели секвенирования. Монада IO - это модель, которая есть во всех других языках программирования; Просто в Хаскеле это явный выбор, а не часть окружающей среды. Монада ST дает вам мутацию памяти ввода-вывода, но без фактического ввода и вывода. С другой стороны, монада State позволяет ограничить ваше состояние одним значением именованного типа.
Что-то действительно изгибающее мозг, см. в этом блоге о монаде отсталого состояния. Государство распространяется в направлении, противоположном «исполнению». Если вы думаете об этом как о монаде состояния, выполняющей одну инструкцию с последующей следующей, тогда «put» отправит значение состояния назад во времени на любой предшествующий «get». На самом деле происходит, когда устанавливается взаимно рекурсивная функция, которая завершается, только если нет парадоксов. Я не совсем уверен, где использовать такую монаду, но она иллюстрирует точку зрения о том, что монады являются моделями вычислений.
Если вы не готовы к этому, просто подумайте о связывании как о перегружаемой точке с запятой. Это продвинет вас довольно далеко.