Что такое монада в 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.
Ответ 8
страница Haskell wikibook имеет хорошее базовое объяснение.