Что такое монада в FP, категорически?

Каждый раз, когда кто-то promises "объясняет монады", мой интерес вызван, только для того, чтобы его заменили разочарованием, когда предполагаемое "объяснение" - это длинный список примеров, оканчивающихся каким-то небрежным замечанием о том, что "математическая теория" за "эзотерическими идеями" "слишком сложно объяснить на этом этапе".

Теперь я прошу об обратном. У меня есть четкое понимание теории категорий, и я не боюсь преследований диаграмм, леммы Йонеды или производных функторов (и действительно, в монадах и дополнениях в категориальном смысле).

Может ли кто-нибудь дать мне четкое и четкое определение того, что монада в функциональном программировании? Чем меньше примеров, тем лучше: иногда одна четкая концепция говорит о более чем ста робких примерах. Хаскелл прекрасно подойдет для демонстрации, хотя я не придирчив.

Ответ 1

Как комплимент Карлу, Монада в Хаскелле (теоретически):

class Monad m where
  join :: m (m a) -> m a
  return :: a -> m a
  fmap :: (a -> b) -> m a -> m b

Обратите внимание, что "bind" (>>=) можно определить как

x >>= f = join (fmap f x)

Согласно Haskell Wiki

Монада в категории C является тройкой (F: C → C, η: Id → F, μ: F ∘ F → F)

... с некоторыми аксиомами. Для Haskell fmap, return и join совпадают с F, η и μ соответственно. (fmap в Haskell определяет функтор). Если я не ошибаюсь, Scala вызывает эти map, pure и join соответственно. (Scala вызывает bind "flatMap" )

Ответ 2

У этого вопроса есть хорошие ответы: Монады как дополнения

Более того, статья "Расчетные монады с категорией категорий" Дерека Элкинса в TMR # 13 должна иметь вид конструкций, которые вы ищете: http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf

Наконец, и, возможно, это действительно самое близкое к тому, что вы ищете, вы можете перейти прямо к источнику и посмотреть оригинальные статьи Могги по этой теме с 1988-91 года: http://www.disi.unige.it/person/MoggiE/publications.html

См., в частности, "Понятия об вычислениях и монадах".


Мое собственное Я уверен, что слишком сжатое/неточное:

Начните с категории Hask, объекты которой являются типами Haskell и морфизмы которых являются функциями. Функции также являются объектами в Hask, а также являются продуктами. Итак, Hask декартово замкнуто. Теперь представьте стрелку, отображающую каждый объект в Hask до MHask, который является подмножеством объектов в Hask. Ед. изм! Затем введите стрелку, отображающую каждую стрелку на Hask стрелке на MHask. Это дает нам карту и делает MHask ковариантный эндофон. Теперь представьте стрелку, отображающую каждый объект в MHask, который генерируется из объекта в MHask (через единицу) объекту в MHask, который его генерирует. Присоединиться! И из этого, MHask является монадой (и моноидальным эндофоном, точнее).

Я уверен, что есть причина, по которой это из-за недостатка, поэтому я действительно направляю вас, если вы ищете формализм, в документы Могги в частности.

Ответ 3

Хорошо, используя терминологию Haskell и примеры...

Монада в функциональном программировании представляет собой шаблон композиции для типов данных с типом * -> *.

class Monad (m :: * -> *) where
    return :: a -> m a
    (>>=)  :: m a -> (a -> m b) -> m b

(В классе больше, чем в Haskell, но это важные части.)

Тип данных - это монада, если он может реализовать этот интерфейс, удовлетворяя при этом три условия в реализации. Это "законы монады", и я оставлю это до тех давних объяснений для полного объяснения. Я суммирую законы, поскольку "(>>= return) является тождественной функцией, а (>>=) ассоциативна". Это действительно не более того, даже если это можно выразить более точно.

И это вся монада. Если вы можете реализовать этот интерфейс, сохранив эти поведенческие свойства, у вас есть монада.

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

Что менее очевидно, так абстрактно, как интерфейс, он позволяет в целом моделировать любой шаблон потока управления, независимо от реальной реализации монады. Вот почему в пакете Control.Monad в библиотеке GHC base есть такие комбайнеры, как when, forever и т.д. И поэтому способность явно абстрагироваться от любой реализации монады является мощной, особенно при поддержке системы типов.

Ответ 4

Я не знаю, о чем говорю, но вот мое взятие:

Монады используются для представления вычислений. Вы можете придумать нормальную процессуальную программу, которая в основном представляет собой список утверждений, как совокупность составленных вычислений. Монады - это обобщение этой концепции, позволяющее вам определить, как складываются утверждения. Каждое вычисление имеет значение (оно может быть только ()); монада просто определяет, как ведет себя поведение, затраченное на ряд вычислений.

Нотация действительно делает это ясным: это в основном специальный тип языка, основанный на операторах, который позволяет вам определять, что происходит между операторами. Это как если бы вы могли определить, как ";" работал на языках C-типа.

В этом свете все моны, которые я использовал до сих пор, имеют смысл: State не влияет на значение, но обновляет второе значение, которое передается от вычисления к вычислению в фоновом режиме; Maybe замыкает значение, если оно когда-либо встречается с Nothing; List позволяет вам иметь переменное количество пройденных значений; IO позволяет безопасно пропускать нечистые значения. Более специализированные монады, которые я использовал, такие как Gen и парсеры Parsec, также похожи.

Надеюсь, это ясное объяснение, которое не полностью вне базы.

Ответ 5

Вы должны прочитать статью Евгения Могги "Понятия о вычислениях и монадах", которые объясняют предложенную роль монад, чтобы структурировать денотационную семантику эффективных языков.

Также возникает связанный с этим вопрос:

Ссылки для изучения теории чистых функциональных языков, таких как Haskell?

Поскольку вы не хотите размахивать руками, вы должны читать научные статьи, а не ответы на форуме или учебные пособия.

Ответ 6

Монада является моноидом в категории endofunctors, в чем проблема?.

В отличие от юмора, я лично считаю, что монады, поскольку они используются в Haskell и функциональном программировании, лучше понимаются с точки зрения монад-как-интерфейс (как в ответах Карла и Дэн), а не из монад с точки зрения теории. Должен признаться, что я действительно только усвоил всю монадскую вещь, когда мне пришлось использовать монадический библиотека с другого языка в реальном проекте.

Вы упомянули, что вам не нравились все учебные пособия "много примеров". Кто-нибудь когда-либо указывал вам на бумагу Awkward squad? Он сосредоточен в монаде IO, но введение дает хорошее техническое и историческое объяснение того, почему концепция монады была охвачена Haskell в первую очередь.

Ответ 7

Поскольку вы понимаете монады в теоретическом смысле, я интерпретирую ваш вопрос как представление о монадах в функциональном программировании. Таким образом, мой ответ избегает любого объяснения того, что такое монада, или какой-либо интуиции о ее значении или использовании.

Ответ. В Haskell монада представлена ​​на внутреннем языке для некоторой категории как (интернализованные) карты тройки Клейсли.

Объяснение: Трудно быть точным в отношении свойств категории "Hask", и эти свойства в значительной степени не имеют отношения к пониманию представления Haskell о монадах. Вместо этого, для этого обсуждения, более полезно понять Haskell как внутренний язык для некоторой категории C. Функции Haskell определяют морфизмы в C, а типы Haskell - это объекты в C, но конкретная категория, в которой эти определения сделаны, несущественна.

Параметрические типы данных, например. data F a = ..., являются объектными отображениями, например. F : | С | -> | С |.

Обычное описание монады в Haskell находится в Kleisli triple (или расширение Kleisli):

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

где:

  • m - это отображение объекта m :| C | -> | C |
  • return - операция устройства на объектах
  • >>= (произносится как "bind" от Haskellers) является операцией расширения для морфизмов, но с первыми двумя параметрами, замененными (см. обычную сигнатуру расширения (-)* : (a -> m b) -> m a -> m b)

(Эти карты сами интернализируются как семейства морфизмов в C, что возможно, так как m :| C | -> | C |).

Haskell do -нотация (если вы встретили это), поэтому является внутренним языком для категорий Kleisli.