Что такое монады?
От: Аноним  
Дата: 22.11.10 12:24
Оценка:
Недавно была статья на Хабре про монады
Заинтересовался темой, прочитал еще несколько статей про монады в различных блогах, статью на вики, но так ничего и не понял, не уловил сути:)
Про основные концепции ФП (лямбды, замыкания и т.п.) в курсе, но применительно к гибридным языкам типа Scala/Nemerle. C Lisp и Haskell не знаком, даже с синтаксисом.
Хочется понять, что же это за монады, стрелки и т.п., и могли бы они существовать в простом си-подобном гибридном языке (т.е. в таком, где в основе лежит императивная парадигма, сишный синтаксис, но поддерживается и функциональное программирование).

Понять именно с точки зрения программиста/кодера, а не математика:)
Re: Что такое монады?
От: Lloyd Россия  
Дата: 22.11.10 12:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Хочется понять, что же это за монады, стрелки и т.п., и могли бы они существовать в простом си-подобном гибридном языке (т.е. в таком, где в основе лежит императивная парадигма, сишный синтаксис, но поддерживается и функциональное программирование).


На Lambda the Ultimate положительно отзываются о You Could Have Invented Monads!
Re: Что такое монады?
От: Аноним  
Дата: 22.11.10 12:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Хочется понять, что же это за монады .. с точки зрения программиста/кодера


Моноиды в категории эндофункторов, где объекты — типы, а стрелки — функции.

А>могли бы они существовать в простом си-подобном гибридном языке


Разумеется. Но без поддержки со стороны языка (аналог тайпклассов, или прямая поддержка полиморфизма ранга 2) — это будет довольно громоздкая хрень, не способствующая облегчению чтения кода.

На скалке их сделать не проблема, даже на сишарпе можно, через LINQ.
Re: Что такое монады?
От: MigMit Россия http://migmit.vox.com
Дата: 22.11.10 12:47
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Хочется понять, что же это за монады, стрелки и т.п., и могли бы они существовать в простом си-подобном гибридном языке (т.е. в таком, где в основе лежит императивная парадигма, сишный синтаксис, но поддерживается и функциональное программирование).


В Scala оно есть. В F# тоже.
Re: Что такое монады?
От: jazzer Россия Skype: enerjazzer
Дата: 22.11.10 12:55
Оценка: 9 (1)
Здравствуйте, Аноним, Вы писали:

А>Недавно была статья на Хабре про монады

А>Заинтересовался темой, прочитал еще несколько статей про монады в различных блогах, статью на вики, но так ничего и не понял, не уловил сути

А>Понять именно с точки зрения программиста/кодера, а не математика


На RSDN неплохая статья, имхо
http://www.rsdn.ru/article/funcprog/monad.xml
Автор(ы): Евгений Кирпичев aka jkff
Дата: 28.12.2008
Статья рассказывает о том, что такое монады Haskell, приводятся примеры, иллюстрирующие эту концепцию.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Что такое монады?
От: Аноним  
Дата: 22.11.10 13:22
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Моноиды в категории эндофункторов, где объекты — типы, а стрелки — функции.

А>>могли бы они существовать в простом си-подобном гибридном языке
А>Разумеется. Но без поддержки со стороны языка (аналог тайпклассов, или прямая поддержка полиморфизма ранга 2) — это будет довольно громоздкая хрень, не способствующая облегчению чтения кода.

Давайте пофантазируем:) Предложите синтаксис некоего псеводязыка, такой чтобы монады органично (на ваш вкус) вписались в традиционный императивный стиль. Все-таки хочется сначала понять, а уже потом осваивать терминологию:)
Допустим, есть некий простой язык. В нем есть базовые управляющие конструкции (if/else/...), функции (пусть будут "первоклассные" функции, как в ФП, с лямбдами и замываниями), типы (статическая типизация), переменные, константы. Пусть будут структуры и классы как в С++. Т.е. некий стандартный общепризнанный набор, понятный большинству.
Достаточно ли этого? Если недостаточно — то предложите чего не хватает...

И что такое "эндофункторы"?
Что такое "тайпклассы"?
Что такое "полиморфизм ранга 2"?
"Объекты-типы, а стрелки-функции", это какое-то метапрограммирование над типами? Т.е. у меня (уж простите за простоту) есть например объект "int", есть другой объект "float", и я могу написать функцию ("стрелку"), которая что-то с ними делает? И что можно с ними сделать?
Понимаю что вопросы глупые, но хочется въехать, причем не удаляясь от реального программирования в дебри математики, а скорее наоборот —

Из того, что я понял прочитав статьи — монады это какая-то абстракция для "цепочек вычислений". Но это к сожалению ни о чем мне не говорит (точнее, говорит — что можно просто взять и вызвать несколько функций подряд, но ведь ясно что это совсем не то), пока мозг цепляется за привычное и я не могу понять как-бы они могли мне помочь в написании реального кода.
Re: Что такое монады?
От: Klapaucius  
Дата: 22.11.10 13:29
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>Недавно была статья на Хабре про монады

А>Заинтересовался темой, прочитал еще несколько статей про монады в различных блогах, статью на вики, но так ничего и не понял, не уловил сути

Корень проблемы я выделил жирным шрифтом. Понимать монады очень просто. Понимать блогпосты про монады практически невозможно — не стоит даже и пытаться. Все что можно из них извлечь — это странные продукты подсознания автора монадного тьюториала и его детские страхи. Зачем вам это? В общем, я предупредил.

А>Хочется понять, что же это за монады, стрелки и т.п., и могли бы они существовать в простом си-подобном гибридном языке (т.е. в таком, где в основе лежит императивная парадигма, сишный синтаксис, но поддерживается и функциональное программирование).


Это смотря что понимать под поддержкой. Монады могут выражаться в системе типов (Haskell, Scala) — для этого в языке должен быть параметрический полиморфизм с возможностью абстрагироваться от конструктора типа, иметь поддержку в языке в виде синтаксического сахара (Haskell, Scala, С#, F#) и т.д. Как своего рода "паттерн" (мы же программистам объясняем?) они могут существовать почти в любом языке.

А>Понять именно с точки зрения программиста/кодера, а не математика


С точки зрения программиста монада это абстрактный контейнер с тремя функциями.
map — заменяет содержимое контейнера без изменения самого контейнера. Заменяем каждый гвоздь в коробке шурупом, каждый int в массиве float-ом — так map и работает.
unit — берет элемент и возвращает контейнер с одним этим элементом. Делаем из гвоздя коробку с одним гвоздем. Делаем из int массив из одного int.
join — уменьшает вложенность контейнеров — из коробки коробок гвоздей делает коробку с гвоздями (из массива массивов int-ов — массив int-ов). Ну или из коробки коробок коробок гвоздей делаем коробку коробок гвоздей. Это уже сложная концепция, доступная только программистам и более абстрактно развитым товарищам; обычный человек будет обескуражен тем, как в одну коробку могли поместиться несколько точно таких-же коробок. Впрочем, простая замена коробок коробок на мешки мешков или пакеты пакетов позволяет совершить абстрактно-теоретико-категориальный прорыв.

Необязательные сведения: мы имеем иерархию абстрактных контейнеров, которые эти функции наследуют так:
функтор(map) <- pointed functor (map, unit) <- монада (map, unit, join).

Еще более необязательная информация:
между pointed functor и монадой в этой иерархии аппликативный функтор. Также можно добавить к монаде ноль — пустую коробку и плюс — берем две коробки (эти две коробки сами не в коробке!) и складываем их содержимое в одну такую же коробку. Ноль, естественно, для этого плюса будет нейтральным элементом.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Что такое монады?
От: jazzer Россия Skype: enerjazzer
Дата: 22.11.10 13:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Понять именно с точки зрения программиста/кодера, а не математика


Еще можешь посмотреть видео-лекцию Eric Meijer на C9, которая Functional Parsers — он там показывает, как естественным образом получаются монады.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Что такое монады?
От: Аноним  
Дата: 22.11.10 14:18
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>С точки зрения программиста монада это абстрактный контейнер с тремя функциями.

K>map — заменяет содержимое контейнера без изменения самого контейнера. Заменяем каждый гвоздь в коробке шурупом, каждый int в массиве float-ом — так map и работает.
K>unit — берет элемент и возвращает контейнер с одним этим элементом. Делаем из гвоздя коробку с одним гвоздем. Делаем из int массив из одного int.
K>join — уменьшает вложенность контейнеров — из коробки коробок гвоздей делает коробку с гвоздями (из массива массивов int-ов — массив int-ов). Ну или из коробки коробок коробок гвоздей делаем коробку коробок гвоздей. Это уже сложная концепция, доступная только программистам и более абстрактно развитым товарищам; обычный человек будет обескуражен тем, как в одну коробку могли поместиться несколько точно таких-же коробок. Впрочем, простая замена коробок коробок на мешки мешков или пакеты пакетов позволяет совершить абстрактно-теоретико-категориальный прорыв.

Спасибо, это все формально понятно. Но что это реально дает при программировании? Самое главное — зачем все это, как эта концепция (при должной поддержке со стороны языка — считаем что мы авторы языка и можем делать что хотим) реально облегчит жизнь программистам?
Пока я из Вашего объяснения вижу некую абстракцию типа хитрого контейнера для хранения данных, причем непонятно в каких случаях ее целесообразно применять, и чем он лучше обычных массивов/списков и т.д. Ясно что я чего-то недопонимаю, и когда пойму мне самому смешно будет это читать:) Но что именно?
Re: Что такое монады?
От: Temoto  
Дата: 22.11.10 14:29
Оценка:
А>Недавно была статья на Хабре про монады
А>Заинтересовался темой, прочитал еще несколько статей про монады в различных блогах, статью на вики, но так ничего и не понял, не уловил сути
А>Про основные концепции ФП (лямбды, замыкания и т.п.) в курсе, но применительно к гибридным языкам типа Scala/Nemerle. C Lisp и Haskell не знаком, даже с синтаксисом.
А>Хочется понять, что же это за монады, стрелки и т.п., и могли бы они существовать в простом си-подобном гибридном языке (т.е. в таком, где в основе лежит императивная парадигма, сишный синтаксис, но поддерживается и функциональное программирование).

А>Понять именно с точки зрения программиста/кодера, а не математика


Это интерфейс с двумя методами:
— "поднять в монаду". Давайте называть этот метод 'pure'. Функция от одного аргумента. На входе какое-то значение, на выходе это же значение, но помеченое другим типом. На Си этот новый тип можно сделать через typedef.
— "применить функцию к значению в монаде" или "совершить действие". В энергичном языке, думаю, уместо было бы название 'apply'. Функция от двух аргументов. На входе монадическое значение (полученное из первой функции) и собственно функция-действие, которое нужно применить к первому аргументу. На выходе новое монадическое значение, то есть изменённое функцией-действитем. Ну, эта особенность с "на выходе новое", она в общем-то нужна в языках с одним присваиванием, в остальных можно передать монадическое значение по ссылке и поменять его.

Всё остальное относится к конкретным монадам и рассматривать их нужно отдельно.

Собственно, весь смысл в двух вещах:
1) новый тип даёт инкапсуляцию
2) явная передача функции-действия развязывает (decoupling) их от собственно процесса применения действия. И основная фишка в том, что этот, своего рода, late binding может происходить не в рантайме (как в технологии COM, если знаете), а во время компиляции. С хорошей поддержкой полиморфизма в системе типов можно:
— гибко определять как будут выполняться одинаковые действия в разных монадах
— повторно использовать однажды определённые действия в новых монадах.
Похоже, этот пункт получился сумбурным. Надеюсь на понимание.

В каком-то странном смысле, примером является read/write/close из Си. Они работают с абстрактными файловыми дескрипторами, которые получаются из разных "чистых" значений (путь к файлу, sockaddr). Это с большой натяжкой и кучей оговорок можно назвать file descriptor monad.
ftell(fd) могла бы быть реализована так
apply(fd, (function (FILE* file) {
  return file.position;
}))

, то есть в одну глобальную функцию, перегруженную по типам, передаётся fd и функция от одного аргумента, которая принимает этот самый fd и что-то с ним делает. `file`, в данном случае, будет являться тем самым инкапсулированным значением, которое скрыто за fd. apply передаст в анонимную функцию нужное инкапсулированное значение (потому что она перегружена по типам и знает какому fd соответствует какой file). То есть file мог бы взяться, например, отсюда:
typedef struct { int fd; /*скрытое поле*/ FILE* _file; } fd;
function fd pure(Filepath path) {
  return struct {
    fd = new_fd(),
    _file = new_file(path)
  };
}


По поводу существования в си-подобном языке. Без поддержки со стороны системы типов инкапсуляция не получится. Явная передача действия в какую-то одну глобальную функцию будет выглядеть ужасно громоздко без синтаксического сахара. Хотя, в языках с хорошей поддержкой шаблонов этот сахар можно сделать библиотекой.
Re[3]: Что такое монады?
От: Аноним  
Дата: 22.11.10 17:33
Оценка: 11 (1)
Здравствуйте, Аноним, Вы писали:

А>Достаточно ли этого?


Вполне.

А>И что такое "эндофункторы"?


Функторы из категории в себя. Допустим есть категория, где объекты — типы языка программирования, а морфизмы — функции. Есть конструктор типа vector<a> (обобщенный контейнер). Этот контейнер отображает произвольный тип языка в другой тип этого языка. Например int -> vector<int> или vector<bool> -> vector<vector<bool>>. Поэтому он эндо. Помимо объектов надо отобразить морфизмы, т.е. функции. Поэтому нам еще нужна функция map (a -> b) -> vector<a> -> vector<b>, которая принимает любую функцию вида a -> b из базовой категории, и возвращает функцию vector<a> -> vector<b> из категории, в которую мы отображаем. Конструктор типа vector<a> вместе с функцией map : (a -> b) -> vector<a> -> vector<b> образуют эндофунктор — шнягу, отображающую типы и функции в другие типы и функции.

А>Что такое "тайпклассы"?


Класс типов — шняга для addhoc полиморфизма. Нужна, чтобы можно было писать обобщенные функции для монад. Например, мы хотим сделать фунцию liftM2 (a -> b -> c) -> m<a> -> m<b> -> m<c>, которая принимает функцию от двух аргументов и отображает её в соответствующую функцию от двух агрументов в целевой категории (например отображает функцию сложения чисел в функцию сложения векторов). Она выражается через монадические bind и unit и её вид не зависит от того, используем мы vector<c> или что-то еще. НО если мы запишем её для типа vector — liftM2 : (a -> b -> c) -> vector<a> -> vector<b> -> vector<c> ни с чем кроме векторов она работать не сможет. Поэтому используются классы типов. Например определяется класс "монада":

class Monad m where
bind :: (a -> m b) -> m a -> m b
unit :: a -> m a

и функция (Monad m) => liftM2 (a -> b -> c) -> m a -> m b -> m c, которой похрену какие типы брать, лишь бы они были мондами, т.е. имели соответствующие функции. Это очень похоже на генерик-интерфейсы в джаве или шарпе, но у интерфейсов ранг = 1, т.е. ты можешь написать someMethod<a>(IGenericInterface<a> value), где а является параметром типа, но не можешь someMethod<i, a>(i<a> value) где параметрами являются a и i одновременно.

А>Что такое "полиморфизм ранга 2"?


Это шняга, которая позволяет принимать полиморфные функции, принимающие полиморфные функции. Например такие:
yoba :: (forall a. a -> a) -> Int
yoba f = (f 10) + (f + 20)
Здесь yoba принимает в качестве первого аргумента полиморфную функцию f : a -> a, способную принять любой аргумент и скармливает ей числа (она это может делать, т.к. f — полиморфна). Для монад это нужно, потому что в случае написания обобщенной liftM2, она, фактически, будет принимать полиморфные bind и unit (тайпкласс — это фактически способ передать набор функций). Тайпклассы — это немного меньше, чем полиморфизм ранга 2, но обычно из достаточно для большинства фишечек, вроде обощенных функций для монад.

А>"Объекты-типы, а стрелки-функции", это какое-то метапрограммирование над типами?


Нет, самое обычное программирование.

>Т.е. у меня (уж простите за простоту) есть например объект "int", есть другой объект "float", и я могу написать функцию ("стрелку"), которая что-то с ними делает? И что можно с ними сделать?


Лифтануть функцию в категорию vector<a>, например, чтобы получать из векторов float-ов, вектора int-ов.

А>Из того, что я понял прочитав статьи — монады это какая-то абстракция для "цепочек вычислений".


Это абстракция, позволяющая отображать вычисления из базовой категории в "обогащенную" категорию. Например из категории чистых функций в категорию функций с побочными эффектами.

>как-бы они могли мне помочь в написании реального кода.


Как и любой другой декомпозиционный паттерн. Какую-нибудь общую логику можно засунуть в bind и unit и абстрагироваться от нее. Например, если ты тебе надо написать много кода с callback функциями, в bind можно засунуть связывание callback-ом, тогда код будет выглядеть вот так:

getValue1 >>= \value1 -> getValue2 >>= \value2 -> return value1 + value2

или вот так с сахаром:

do
value1 <- getValue1
value2 <- getValue2
return value1 + value2

а на самом деле там будет выполняться привязка к callback-у и прочая хрень. Пример — asynchronous workflow в F# — позволяют писать неблокирующий IO почти так же, как блокирующий, попробуй ради интереса пописать неблокирующий IO на IAsyncResult в старом стиле, почувствуй разницу.
Re[3]: Что такое монады?
От: Klapaucius  
Дата: 23.11.10 11:32
Оценка: 53 (8)
Здравствуйте, <Аноним>, Вы писали:

А>Пока я из Вашего объяснения вижу некую абстракцию типа хитрого контейнера для хранения данных, причем непонятно в каких случаях ее целесообразно применять, и чем он лучше обычных массивов/списков и т.д. Ясно что я чего-то недопонимаю, и когда пойму мне самому смешно будет это читать Но что именно?


Это не абстракция "типа хитрого контейнера" это абстракция от контейнера, как, например, итератор — абстракция от контейнера. И массив и список это монады.

А>Спасибо, это все формально понятно. Но что это реально дает при программировании? Самое главное — зачем все это, как эта концепция (при должной поддержке со стороны языка — считаем что мы авторы языка и можем делать что хотим) реально облегчит жизнь программистам?


Двумя способами.
Первый способ
заключается в том, что мы разделяем логику и какую-то специфическую "обвязку" этой логики.
Представьте, что у нас есть функция f, которая что-то делает с двумя значениями, объектами. Эти два объекта мы можем получать разными способами. Допустим, что мы ищем их в некоем хранилище, базе данных, коллекции, т.е. они результат поиска, запроса. Можем найти, а можем и не найти.
X x = FindX();
Y y = FindY();
if(x.NotNull() && y.NotNull()) // если нужные нам значения получены
    return f(x, y); // вычисляем результат
else
  return null; // результат получить не можем, возвращаем ничего

Тут логика перепутана с проверкой возвращаемых значений, да и проверки реализуются для каждого использования поиска, по месту.
Разделяется и повторно используется она монадой Maybe
do {
    x <- FindX();
    y <- FindY();
    return f (x, y);
}

все, теперь проверки где-то за кадром, пишутся они один раз и потом работают.
Допустим, мы хотим получить результаты f для некоего набора значений. Проверить, например, функцию f на ее области определения или для каких-то особых случаев.
List<Z> result = new List<Z>();
for(X x in xs) {
    for(Y y in ys) {
        result.Add(f(x, y));
    }
}

Проход по наборам иксов и игреков также можно отделить от логики.
List<Z> result = do {
    x <- xs;
    y <- ys;
    return f(x, y);
}

Похоже на декартово произведение, записанное в нотации для множеств, что собственно нам и надо.
Разумеется, одна реализация интерфейса-монады для списка позволит писать и так
do {
    a <- alist;
    b <- blist;
    c <- clist;
    return foo(a,b,c);
}

т.е. за кулисами нашей монады могут быть циклы любой пложенности, каждый раз реализовывать работу с несколькими списками по месту нам больше не понадобится.
Точно также все будет работать и для других монад:
Парсим строку, получаем значения x и y, возращем результат применения f. Если x и y не распарсились — возвращаем ошибку парсинга.
do {
    x <- ParseX();
    y <- ParseY();
    return f (x, y);
}

Получаем значения по сети, ждем, пока придут оба, потом возвращаем результат применения f.
do {
    x <- Get("www.x.org");
    y <- Get("www.y.net");
    return f (x, y);
}

И так далее.
Более того, для монады можно реализовать функции, "поднимающие" другие функции в монады.
Parser parser = ParserMonad.Lift(f);

Все, теперь мы превратили функцию f в парсер. Даже do { <- <- ... <- return } писать не обязательно.
Необязательные свдения — для этих примеров достаточно аппликативного функтора — возможности монад несколько шире.
Второй способ
заключается в том, что монады (и функторы) обладают некоторыми свойствами. Что это значит? А вот что.
Все мы изучали в школе свойства сложения, умножения, тригонометрических функций и т.д. Они позволяли упростить некоторое громоздкое выражение и решить задачу.
Программирование — это решение задач. Упрощение там может пригодится, а может пригодится усложнение — оптимизация, но упрощение и усложнение, всякое преобразование кода в программировании это путь по минному полю. Мы можем думать, что отрефактореный код делает то же самое, но это не обязательно так. Как не покрывай код тестами, но покрытие это статистическое и баг может проскочить. Ну и проскакивает. В школе было проще, выражения равны, это доказано "багу" взяться неоткуда.
a*c + b*c == c*(a + b)

Это оптимизация. Мы заменили одну простую операцию и две сложных на одну простую и одну сложную.
Функторы, монады, моноиды и т.д. приводят школьную простоту и железную надежность доказательства в программирование. Если мы гарантируем выполнение простых свойств, то и сложные преобразования больших объемов кода с соблюдением этих простых правил будут корректны.
map f . map g == map f . g

Это свойство функтора (а следовательно и монады) и тоже оптимизация. Мы заменили работу со списком в два прохода эквивалентной работой в один проход.
До этого я писал, в основном, о монадах и функторах, а вопрос был еще и про стрелки. Тут у нас есть стрелки-функции (да, функция это стрелка) и комбинация этих стрелок:
f . g == x |-> g(f(x)) == fun (x) { return g(f(x)); }
//комбинация функций дает нам новую функцию.
id . f == f
//id - нейтральный элемент для ., как 0 нейтральный элемент для +, а 1 для *:
0 + x == x
1 * x == x

Если у нас есть
0 * ОченьСложноеВычисление

то нет смысла делать сложное вычисление — мы уже знаем ответ. Для map тоже есть значение, "отношения" операции map с которым похожи на отношение операции умножения с нулем. это id — функция, которая дает результат равный принимаемому значению.
map id огромныйСписок == id огромныйСписок == огромныйСписок

нет смысла проходить по огромному списку — он не изменится. "Какой-то бред", может подумать читатель "откуда у нас вдруг возьмется функция, которая ничего не делает?". Легко возмется. Есть множество пар действий, которые будучи сгруппированы (мы ведь упрощаем программу-выражение) дадут ничего не делающую функцию. Папример, поворот изображения по часовой стрелке в комбинации с поворотом изображения против часовой стрелки не делает ничего. есть также операции, которые становятся ничего не делающими при повторном применении, в комбинации с самими собой — зеркальное отражение изображения, например.
Другие свойства монад:
map f . unit == unit . f

Для того, чтобы собирать из монад конструкции из первой части, нам нужны специальные операции, которые монады соединяют.
Самая простая из них — рыбка (>=>).
Рыбка, как и . комбинирует стрелки, но не всякие, а стрелки Клейсли, т.е. функции, которые упаковывают значение (предмет) в монаду (коробку). Одну стрелку клейсли мы уже упоминали — это unit. Unit нейтральный элемент для рыбки, как id для . и 0 для +:
unit >=> f == f
f >=> unit == f

Рыбка ассоциативна, как и + и *:
(a >=> b) >=> c == a >=> (b >=> c)
(x + y) + z == x + (y + z)

Самая известная из них — bind (>>=), это когда мы сначала делаем map стрелкой Клейсли, а потом уменьшаем вложенность монад операцией join
m >>= f = join (map (f, m))

unit(a) >>= f == f(a)

кладем a в коробку
[a]

применяем к внутренностям коробки функцию f
[f(a)]

f это стрелка Клейсли, она кладет свой результат в коробку
[[b]]

а теперь джойним коробки
[b]

готово, то же что и просто
f(a) -> [b]

m >>= unit == m

тут все понятно, упаковываем содержимое коробки в коробку, добавляя вложенность коробок, а потом убираем лишнюю вложенность коробок — бессмысленное занятие.
m >>= (x |-> k x >>= h) = (m >>= k) >>= h

Это уже совсем не так весело, вот потому-то и начинать объяснение монад с bind — это ошибка. Смотрите лучше на join и рыбок.
map f m = m >>= unit . f

выражаем map через bind — упаковывая результат функции f в коробку.

Используя такой вот "алгебраический подход", можно рефакторить программы с обоснованной корректностью преобразования при условии выполнении свойств, а также писать, например, наивную реализацию, которую легко придумать и понять, а потом так же корректно трансформировать в реализацию эффективную, но, возможно, неочевидную и плохо читаемую. Пример таких преобразований на небольшой программе продемонстрирован в этой презентации, но материал не простой, не для первого чтения, потому как слайды в презентации перевернуты, ну а что поделать? В equational reasoning царской дороги нет. Также требуется знание синтаскиса и семантики языка haskell, что, конечно, не так сложно, как переворачивание слайдов, но, тем не менее, не совсем легко.

Резюмируя. Фактически, это аналог того процесса, который произошел гораздо раньше в физике. Два тысячелетия философы спорили о том, летит стрела Зенона или не летит, но вот составили набор простых правил и вуаля: производные находит ученик 10-го класса. Т.е. молодое ремесло "программирование" выпускается из детского сада и идет в школу с перспективой поступить в институт, получить диплом и стать обычной инженерной деятельностью. Вроде самолетостроения. Надеюсь, что на этот раз тысячелетий не понадобится.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.