среда, 24 июля 2013 г.

Может быть кто-то расскажет мне про монады?

http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BD%D0%B0%D0%B4%D0%B0_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)

Может быть кто-то расскажет мне про монады?

Идею я примерно понимаю.

Но вот - технические тонкости - что-то не схватываю.

Есть кому, что рассказать? Для "технарей".

С примерами из реальной жизни.

P.S. понятно, что функция - детерминирована относительно её параметров, а монада - нет. И что функцию можно даже кешировать относительно значений её параметров.

P.P.S. Любая глобальная переменная или ввод-вывод это монады? А функция использующая хотя бы одну монаду - тоже монада? Ну по индукции. А значит, что любая "программа" на функциональном языке использующая хотя бы одну монаду - тоже монада? Ну тоже по индукции.. Так?

P.P.P.S. Функция, зависящая от даты/времени - тоже монада?

26 комментариев:

  1. Монаду нельзя сравнивать с функцией - это совсем не функция. И кэшируемость зависит от самой монады.
    Монады(в хаскеле) это такой класс объектов, определённых следующими функциями:
    1) (>>) :: Monad m => m a -> m b -> m b
    Т.е связывание, при котором значение первой монады игнорируется.
    2) (>>=) :: Monad m => m a -> (a -> m b) -> m b
    Т.е связывание, при котором значение из монады 1 передаётся функции, возвращающей монаду 2.
    3) return :: Monad m => a -> m a
    Т.е функция, создающая монаду из значения.
    Ещё есть доп. Функция fail.
    На основании этих функций монады взаимодействуют между собой, и этим функциям доступно кэширование(монада выступает как один из аргументов этих функций).
    Особый случай - монады ST и IO, они специальным образом обрабатываются компилятором.

    Любая "глобальная переменная" это монада, функция использующая монады не обязательно монадическая, т.к некоторые монады предусматривают получение значаения(Монады [a], Maybe a, например). В функциональных языках функции не считаются программами или подпрограммами. Если говорить о монаде IO - то да, честного выхода из неё нет, и все функции работающие с ней должны быть монадическими.
    Про дату и время - всё зависит от того, как построена зависимость(может параметр даты и времени передаётся снаружи).
    Что-либо ещё смогу написать только вечером =)

    ОтветитьУдалить
    Ответы
    1. Простите, но первую часть - вообще не понимаю.

      Удалить
    2. Можно по-русски? На бытовом уровне. Для тупых. А не в закорючках?

      В закорючках - я уже читал :-) И не раз.

      Удалить
    3. "В функциональных языках функции не считаются программами или подпрограммами"

      "Вы на воздушном шаре"

      И что? Какая разница - что чем "считается". Гораздо важнее, что чем - ЯВЛЯЕТСЯ.

      Удалить
    4. Фунукции в ФП действительно не являются подпрограммами. В императивном языке вы работаете с подпрограммами, компилятор не имеет права превратить код во что-либо другое. Хотя он это и делает, но это "обман", и некоторые оптимизации для него не позволительны. В ФП функция это отображение из 'a' в 'b', и совершенно не важно как оно произойдёт, главное что бы оно подчинялось описаным правилам. В реальности вызова функции может и не быть, а для "манёвров" компилятора остаётся максимум места.

      Удалить

  2. Дело тут, похоже, не в чьей-то "тупизне", а в моей неспособности объяснить простым языком. =(
    Ладно, попробую ещё раз:
    Начнём с того что монада это класс типов. Это означает что для всех типов этого класса определены некоторые функции(можно провести аналогию с "интерфейсом" в ООП). Надеюсь тут всё понятно?
    Далее: монада это не обычный "интерфейс", его можно представить как "шаблонный интерфейс" параметризуемый одним параметром.
    IO String - монада с типом String, например.
    IO Int - монада с типом Int
    [Bool] - монада с типом Bool,
    Maybe Int - монада с типом Int.
    итд.
    Далее: что за функции определены в "интерфейсе" монады? Есть три основные функции(одну дополнительную опустим):
    1) Функция ">>". Она берёт две монады(одного типа, IO, например) и возвращает третью монаду того же типа.
    При этом первая и вторая монада могут быть "параметризованы" различными типами, останется только параметр-значение второй.
    Например IO Int >> IO String будет IO String.
    2) Функция ">>=". Производит "связывание" монады и монадической функции. Монадическая функция - это такая функция, которая возвращает монаду.
    Допустим у нас есть функция String -> IO (). Т.е функция принимает строку, и возвращает пустую монаду. Так, например, поступает функция вывода в консоль.
    И у нас есть монада IO String. Так, например, выглядит монада читающая строку из консоли. Связывание "исполняет" монадическую функцию, используя значение из монады.
    IO String >> (String -> IO ()) будет IO ().
    Т.е getLine >>= putStrLn, выведет строку, полученную из ввода. Т.к getLine это монада (IO String), а putStrLn это монадическая функция (String -> IO () ). Скобки () означают пустое значение.
    3) Функция "return". Функция предельно простая - она помещает значение в монаду. Т.е return 1 для IO вернёт IO Int,
    для списка - [Int], для Maybe - Maybe Int.

    Впрочем, не думаю что это объяснение намного лучше предыдущего. Но надеюсь вы хоть общее представление получили. =)

    ОтветитьУдалить
    Ответы
    1. Спасибо. Вот тут - есть над чем подумать.

      Удалить
    2. Я правильно понимаю, что монада это "хинт" компилятору, что "тут начинается недетерминированная зона"?

      Удалить
    3. С точки зрения хаскеля("категории hask") монады - это обычный класс типов. Компилятор обрабатывает специальным образом только "IO" и "ST", другие монады он не трогает. =)

      Удалить
    4. Не очень понимаю - как компилятор может их "не трогать" - ему же важна детерминированность функций. Или я ошибаюсь?

      Удалить
    5. Сцепки "монада - монада". Без выхода. Понимаю. Но "монада - функция". Не понимаю.

      Удалить
    6. Повторю вопрос - что компилятор делает со сцепками "монада - функция"? Или "функция - монада"?

      На "бытовом уровне". Считали из файла (который недетерминированный). Получили значение. Передаём в функцию. Она детерминирована?

      Что с ней делает компилятор? "Изолирует" от детерминированных функций?

      Удалить
    7. Сами по себе монады детерминированны. Монады это просто описание. В случае IO можно сказать что хаскель строит описание действий программы. Компилятор в последствии создаёт из этого описания программу. Т.е с точки зрения хаскеля IO a >> IO b это вполне себе детерминированная функция.
      Обычно соединение монады и монадической функции выглядит так: после того как будет выяснено значение монады, оно будет передано функции, которая вернёт ещё одну монаду. А там они уже радостно соединятся как монада - монада. =)
      Монадическая функция служит только для создания монады.

      Удалить
    8. Ничего не понял...
      А можно пример из реальной жизни? В духе - вот есть задача - вот так её решаем.

      Удалить
    9. Можно. Вот написал парсер конфигураций. Конфигурации представляют собой пары название := значение. В роли значений могут выступать либо строки либо другие конфигурации, указаные в фигурных скобках. Например:
      name1 := "string value";
      name2 := "string value2";
      name3 := {
      name3a := "string value3a";
      name3b := "string value3b";
      };
      Код с комментариями, хотя по мне - они лишние.
      http://pastebin.com/tEiqGVwH

      Это, собственно, пример монады как описания. Т.е сама по себе монада Parser ничего не парсит. Парсит функция "parseTest", используя описание, предоставленное монадой.

      Удалить
    10. Мда. "Не убедил".

      Не в этой жизни видимо.... :-(

      Удалить
    11. В каком плане "не убедил"? У вас есть более выразительные средства для подобного рода операций? Я бы не прочь ознакомиться. =)

      Удалить
    12. Для того, чтобы обсуждать "подобного рода" - надо понимать что там написано. Это во-первых. Китайский язык - может быть и занятен. Но явно - не ВЫРАЗИТЕЛЕН. По-моему вы всё-таки путаете ВЫРАЗИТЕЛЬНОСТЬ с КОМПАКТНОСТЬЮ. Это - не то же самое. Во-вторых - использовать библиотеки - я тоже могу. В ЛЮБОМ языке. В-третьих - так я и не понял - что такое монады и как введение этого понятия помогает нефункциональным вещам стать функциональными. Иначе - непонятно - зачем изобретать какие-то дополнительные понятия.

      Удалить
    13. А вы не понимаете что там написано? Прочитайте описание выше. И, поверьте мне, если бы я хотел компактности, я бы записал компактно(http://pastebin.com/8Sc26dg1). А данный код выигрывает именно по читаемости. Вообще мне сложно представить более читаемый код. Может изобразите? =)
      И я же не говорил что вы не можете использовать библиотеки?
      Монада это не дополнительное понятие. Это такое же понятие как "коллекция", "итератор", итд. А помогает она тем, что может просто описать императивность, последовательность действий. Но именно описать, а не совершить.

      Удалить
    14. Да я понимаю, что там написано.

      Но всё равно - разговор слепого с глухим.

      "Может изобразите?" - типа на слабо? Нет, не изображу. Я не привык - на слабо.

      Да и я лично продолжаю считать это "набором закорючек". Удивляюсь я. Зачем люди придумывают себе сложности, а потом героически их преодолевают. А потом рассказывают, что "это выразительно".

      НЕ выразительно.

      В общем - про монады - не рассказали :-(

      Удалить
    15. >"Может изобразите?" - типа на слабо? Нет, не изображу. Я не привык - на слабо.
      На самом деле я специально выбрал для примера парсинг текста, т.к считаю что у вас в этом деле много опыта. Ну что ж - коль не хотите, это ваше дело. Никто вас не заставляет, и никто не хочет отнимать у вас время. =)
      >В общем - про монады - не рассказали :-(
      Ну, я хотя бы попробовал. =)

      Удалить
    16. Спасибо конечно. Попытались.

      Если уж про "парсеры" и выразительность, то по-моему выразительнее БНФ - никто пока ничего не придумал.

      Пример декларативности по-моему - yacc/lexx. Хотя есть у меня к ним вопросы.

      Удалить
    17. Как видите - придумали. =)

      Удалить
    18. По мне - БНФ - нагляднее.

      Но к монадам - я ещё вернусь. Жаль не знаю координат собеседника :-)

      Удалить
    19. Вы меня кстати - простите за резкость, если что. Меня просто иногда бесит - когда люди банальные для них вещи - не могут объяснить мне. Но это - мои проблемы. Я с ними - борюсь.

      Удалить
  3. По-моему - я что-то понял - http://18delphi.blogspot.com/2013/10/blog-post_21.html
    Вопрос - ПРАВИЛЬНО ли я понял?

    ОтветитьУдалить