Описание тега monads

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

Монада в программировании - это составное описание вычислений. Монады - важная конструкция в функциональных языках, таких как 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оператор. По сути, он берет рецепт и некоторую инструкцию, что делать с результатом, а затем добавляет эту инструкцию в конец рецепта. Если вы затем выполните этот рецепт, в результате действительно получится разрезанный на кусочки торт.