Описание тега monads
Монада в программировании - это составное описание вычислений. Монады - важная конструкция в функциональных языках, таких как Haskell.
В Haskell монада - это просто конструктор любого типа m
с двумя функциями,
return :: a → m a -- construct `m a` value from an `a` value,
-- and
(>>=) :: m a → (a → m b) → m b -- "bind": combine `m a` value and
-- `a → m b` value into an `m b` value
следуя нескольким алгебраическим законам. (::
означает "имеет тип".)
Значение типаm a
представляет (описывает)m
-типа, производя a
-тип результат.
Определив
(>=>) :: Monad m => (a → m b) → (b → m c) → a → m c
-- f g x
(f >=> g) x = f x >>= g -- a.k.a. "Kleisli composition"
законы Монад:
return >=> g = g -- left identity
f >=> return = f -- right identity
f >=> (g >=> h) = (f >=> g) >=> h -- associativity
Эти типы значений могут использоваться для представления широкого спектра различных задач, включая: ввод-вывод, продолжения, сопрограммы, недетерминизм, обработку ошибок, изменяемое состояние, синтаксический анализ и многое другое (каждый со своим конкретным выбором для m
). Кроме того, они особенно полезны для встраивания простых DSL в функциональный язык, такой как Haskell. Фактически, можно сказать, что монады в определенном смысле являются EDSL.
Точнее,
отображаемые описания вычислений - это Функторы, имеющие
fmap :: (a → b) → m a → m b
операция, как будто позволяя нам писатьfmap f c = do { x <- c; return (f x) }
составные отображаемые описания вычислений - это Прикладные Функторы, имеющие
(<*>) :: m (a → b) → m a → m b
операции, концептуально позволяющиеc1 <*> c2 = do { x <- c1; y <- c2; return (x y) }
тогда как всякий раз, когда у нас есть составные отображаемые конструкторы описания вычислений, то есть вещи типа
a → m b
составной с оператором композиции Клейсли>=>
, поэтому мы можем написатьc >>= g = do { x <- c; y <- g x; return y }
,тогда у нас есть Монада.
Чтобы процитировать пользователя: leftaroundabout от сюда:
... [] часто цитируемая аналогия состоит в том, что действие [т.е. монадическое значение типа
IO a
] похож на рецепт торта, результат [типаa
] - это сам торт.Применение [функции] непосредственно к действию ввода-вывода было бы похоже на то, как если бы вы взяли нож, чтобы разрезать рецепт на кусочки, и ожидаете, что затем вы сможете использовать этот рецепт для выпекания готового торта.
Ясно, что это не так. Сначала вам нужно выполнить (связать) действие ввода-вывода, прежде чем вы сможете манипулировать результатом.
В качестве альтернативы вы можете использовать
fmap
оператор. По сути, он берет рецепт и некоторую инструкцию, что делать с результатом, а затем добавляет эту инструкцию в конец рецепта. Если вы затем выполните этот рецепт, в результате действительно получится разрезанный на кусочки торт.