Исторически Монады являются конструкцией, исходящей из теории категорий, абстрактной области математики. Сообщество функционального программирования в конечном итоге обнаружило, как Монады могут быть использованы для формализации нескольких полезных вещей, таких как побочные эффекты. Однако даже в таком многопарадигмальном языке, как C++, есть несколько конструкций, которые оказываются Монадами, как<std::optional>,<std::vector>и другие.
Каждый пытается ввести 4 с другой аналогией, и большинство людей терпят неудачу. Это так называемая ошибкаМонады. Мы постараемся избежать этой ловушки, не представляя конкретной интуиции, а представим, что такое монады математически. Для конкретных интуиций мы позволим читателям, которые являются новичками в этой концепции, прочитать одно из многих превосходных учебных пособий, доступных в Интернете. Поначалу понимание монад может занять некоторое время, но как только вы его получите, многие шаблоны станут очевидными монадами.
Существуют различные способы определения Монады; Haskell использует функцию под названием<bind><>>=>и другую под названием<return>(она не имеет ничего общего с утверждением C++<return>). Затем они вводят отношения, которые должны быть удовлетворены, чтобы тип был монадой с этими функциями. Математики иногда используют функцию, называемую<join>, и другую функцию, называемую<unit>, или они также иногда используют другие теоретические конструкции категории, такие как адъюнкции функтора и категория Клейсли.
Эта библиотека использует комплексный подход. Во-первых, мы используем функцию<flatten>(эквивалент 14) вместе с функцией<lift>из<Applicative>(эквивалент 17) для введения понятия монадической функциональной композиции. Затем мы пишем свойства, которые должны быть удовлетворены монадой, используя этого оператора монадной композиции, потому что мы чувствуем, что он показывает связь между монадами и моноидами более четко, чем другие подходы.
Грубо говоря, мы скажем, что<Monad>— это<Applicative>, который также определяет способ составления функций, возвращающих монадический результат, а не только возможность составления функций, возвращающих нормальный результат. Затем мы попросим, чтобы эта композиция была ассоциативной и имела нейтральный элемент, как и обычная функциональная композиция. Для обычного состава нейтральным элементом является функция тождества<id>. Для монадического состава нейтральным элементом является функция<lift>, определяемая<Applicative>. Эта конструкция проясняется в законах ниже.
Note
Monads are known to be a big chunk to swallow. However, it is out of the scope of this documentation to provide a full-blown explanation of the concept. The Typeclassopedia is a nice Haskell-oriented resource where more information about Monads can be found.
Minimal complete definitions
Во-первых,<Monad>должно быть<Functor>и<Applicative>. Также должна быть предусмотрена реализация<flatten>или<chain>, удовлетворяющая нижеприведенным законам монадического состава.
Note
The ap method for Applicatives may be derived from the minimal complete definition of Monad and Functor; see below for more information.
Laws
Для упрощения написания законов мы используем сравнение функций. Для двух функций<f>и<g>мы определяем
При обычном составе функций нам даются две функции \(f : A \to B \) и \(g : B \to C \), и мы должны произвести новую функцию \( compose (g, f) : A \to C \). Этот состав функций является ассоциативным, что означает, что
В этом нет ничего нового, если вы читаете 30 законов. Теперь мы можем наблюдать, что вышеизложенное эквивалентно утверждению, что функции с оператором композиции образуют<Monoid>, где нейтральный элемент является функцией идентификации.
Учитывая<Applicative><F>, что, если бы мы хотели составить две функции \(f : A \to F(B) \) и \(g : B \to F(C) \)? Когда<Applicative><F>также является<Monad>, такие функции, принимающие нормальные значения, но возвращающие монадические значения, называютсямонадическими функциями. Для их составления мы, очевидно, не можем использовать нормальную функциональную композицию, поскольку домены и кодомены<f>и<g>не соответствуют должным образом. Вместо этого нам понадобится новый оператор – назовем его<monadic_compose>:
\[ \mathtt{monadic\_compose} : (B \to F(C)) \times (A \to F(B)) \to (A \to F(C)) \]
Как мы можем реализовать эту функцию? Так как мы знаем, что<F>является<Applicative>, то у нас есть только<transform>(из<Functor>), и<lift>и<ap>(из<Applicative>). Следовательно, единственное, что мы можем сделать в этот момент, уважая подписи<f>и<g>, это установить<x>тип<A>.
<f(x)><F(B)>, так что мы можем нанести на него<g><B>. Это даст нам результат типа<F(F(C))>, но то, что мы хотели, было результатом типа<F(C)>, чтобы уважать подпись<monadic_compose>. Если бы у нас был шутник типа \(F(F(C)) \to F(C)\), мы могли бы просто установить
И мы были бы счастливы. Оказывается,<flatten>именно этот шутник. Теперь мы хотим, чтобы наш шутник удовлетворил некоторые свойства, чтобы убедиться, что эта композиция ассоциативна, как и наша обычная композиция. Эти свойства немного громоздки, поэтому мы не будем делать это здесь. Также нам понадобится какой-то нейтральный элемент для композиции. Этот нейтральный элемент не может быть обычной функцией идентификации, потому что он не имеет правильного типа: наш нейтральный элемент должен быть функцией типа \( X \to F(X) \), но функция идентификации имеет тип \( X \to X \). Сейчас самое время заметить, что<lift>из<Applicative>имеет точно правильную подпись, и поэтому мы возьмем это за наш нейтральный элемент.
Сейчас мы готовы сформулировать законы<Monad>с помощью этого оператора состава. Для a<Monad><M>и функций \(f : A \to M(B) \), \(g : B \to M(C) \) и \(h : C \to M(D) \) необходимо выполнить следующее:
Feed a monadic value into a monadic computation.Given a monadic value and a monadic function, chain feeds the monadic value into the function, thus performing some Monad-specific effects, and returns the result. An implementation of chain must satisfy. More...
Collapse two levels of monadic structure into a single level.Given a monadic value wrapped into two levels of monad, flatten removes one such level. An implementation of flatten must satisfy. More...
Composition of monadic functions.Given two monadic functions f and g, monadic_compose returns a new function equivalent to the composition of f with g, except the result of g is chained into f instead of simply passed to it, as with normal composition. monadic_compose satisfies. More...
Tap inside a monadic chain.Given a function f, tap<M> returns a new function which performs f on its argument and then returns the argument lifted in the MMonad. Combined with the property that chain(m, lift<M>) == m, this provides a way of executing an action inside a monadic chain without influencing its overall result. This is useful to e.g. insert debug statements or perform actions that are not tied to the chain but that need to be executed inside of it. More...
Подать монадическое значение в монадическое вычисление. Учитывая монадическое значение и монадическую функцию,<chain>подает монадическое значение в функцию, таким образом, выполняя некоторые эффекты, специфичные для монады, и возвращает результат. Выполнение<chain>должно быть выполнено.
Для монады<M>, при данном монадическом значении типа<M(A)>и монадической функции \(f : A \to M(B) \),<chain>имеет подпись \( \mathtt{chain} : M(A) \times (A \to M(B)) \to M(B) \.
Parameters
xs
Монадическое значение, подлежащее подаче на функцию<f>.
f
Функция, принимающая нормальное значение в структуре<xs>и возвращающая монадическое значение. Эта функция называется<f(x)>, где<x>является элементом структуры<xs>.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Два уровня монадической структуры распадаются на один уровень. Учитывая монадическое значение, заключенное в два уровня монады,<flatten>удаляет один такой уровень. Реализация<flatten>должна удовлетворять.
Состав монадных функций. Учитывая две монадические функции<f>и<g>,<monadic_compose>возвращает новую функцию, эквивалентную композиции<f>с<g>, за исключением того, что результат<g>является<chain>в<f>вместо того, чтобы просто перейти к нему, как с нормальной композицией.<monadic_compose>удовлетворяет.
Unlike compose, monadic_compose does not generalize nicely to arities higher than one. Hence, only unary functions may be used with monadic_compose.
Signature
Учитывая<Monad><M>и две функции \(f : B \to M(C) \) и \(g : A \to M(B) \), подпись \( \mathtt{monadic\_compose} : (B \to M(C)) \times (A \to M(B)) \to (A \to M(C)) \.
Parameters
f
Монадическая функция с подписью \(B \to M(C)\).
g
Монадическая функция с подписью \(A \to M(B)\).
Note
This method is not tag-dispatched, so it can't be customized directly.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Нажмите внутри монадической цепи. При наличии функции<f><tap<M>>возвращает новую функцию, которая выполняет<f>на ее аргументе, а затем возвращает аргумент, поднятый в<M><Monad>. В сочетании со свойством<chain(m, lift<M>) == m>это обеспечивает способ выполнения действия внутри монадической цепи без влияния на ее общий результат. Это полезно, например, для вставки заявлений отладки или выполнения действий, которые не привязаны к цепи, но которые должны быть выполнены внутри нее.
Note
Since C++ is not a pure language, it is possible to perform side effects inside the f function. Actually, side effects are the only reason why one might want to use tap. However, one should not rely on the side effects being done in any specific order.
Template Parameters
M
(111) Монады в цепочке монад.
Parameters
f
Функция, выполняемая внутри монадической цепи. Она будет называться<f(x)>, где<x>является значением внутри предыдущей монады в цепи. Результат<f>всегда отбрасывается.
Example
// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
Статья Boost.Hana: Monad раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.