Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Boost.Hana: Monad

Boost , ,

Boost.Hana  1.0.1
Your standard library for metaprogramming
Понятие<Monad>представляет<Applicative>с возможностью сплющивания вложенных уровней структуры.

Исторически Монады являются конструкцией, исходящей из теории категорий, абстрактной области математики. Сообщество функционального программирования в конечном итоге обнаружило, как Монады могут быть использованы для формализации нескольких полезных вещей, таких как побочные эффекты. Однако даже в таком многопарадигмальном языке, как 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 == g if and only if f(x) == g(x) for all x

При обычном составе функций нам даются две функции \(f : A \to B \) и \(g : B \to C \), и мы должны произвести новую функцию \( compose (g, f) : A \to C \). Этот состав функций является ассоциативным, что означает, что

compose(h, compose(g, f)) == compose(compose(h, g), f)

Кроме того, эта композиция имеет элемент идентичности, который является функцией идентификации. Это просто означает, что

compose(f, id) == compose(id, f) == f

В этом нет ничего нового, если вы читаете 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>.

monadic_compose(g, f)(x) = transform(f(x), g)

<f(x)><F(B)>, так что мы можем нанести на него<g><B>. Это даст нам результат типа<F(F(C))>, но то, что мы хотели, было результатом типа<F(C)>, чтобы уважать подпись<monadic_compose>. Если бы у нас был шутник типа \(F(F(C)) \to F(C)\), мы могли бы просто установить

monadic_compose(g, f)(x) = joker(transform(f(x), g))

И мы были бы счастливы. Оказывается,<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) \) необходимо выполнить следующее:

// associativity
// right identity
monadic_compose(f, lift<M(A)>) == f
// left identity
monadic_compose(lift<M(B)>, f) == f

Это означает, что<M>вместе с монадическим составом является Моноидом, где нейтральный элемент<lift>.

Refined concepts

  1. Functor
  2. Applicative(бесплатная реализацияap)
    Когда удовлетворяется минимальное полное определение дляMonadиFunctor, можно реализоватьapпутем установки
    ap(fs, xs) =цепь(fs,autof) {
    возвратпреобразование(xs, f);
    }
    [ORIG_END] -->

Concrete models

<hana::lazy>,<hana::optional>,<hana::tuple>

Variables

constexpr auto boost::hana::chain
 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...
 
constexpr auto boost::hana::flatten
 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...
 
constexpr auto boost::hana::monadic_compose
 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...
 
template<typename M >
constexpr auto boost::hana::tap
 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 M Monad. 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...
 
constexpr auto boost::hana::then
 Sequentially compose two monadic actions, discarding any value produced by the first but not its effects. More...
 

Variable Documentation

constexpr auto boost::hana::chain

<#include <boost/hana/fwd/chain.hpp>>

Initial value:
= [](auto&& xs, auto&& f) -> decltype(auto) {
return tag-dispatched;
}

Подать монадическое значение в монадическое вычисление. Учитывая монадическое значение и монадическую функцию,<chain>подает монадическое значение в функцию, таким образом, выполняя некоторые эффекты, специфичные для монады, и возвращает результат. Выполнение<chain>должно быть выполнено.

chain(xs, f) == flatten(transform(xs, f))

Signature

Для монады<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)
namespace hana = boost::hana;
BOOST_HANA_CONSTEXPR_LAMBDA auto deref = [](auto x) -> decltype(*x) {
return *x;
};
BOOST_HANA_CONSTEXPR_LAMBDA auto age = [](auto x) -> decltype(x.age) {
return x.age;
};
BOOST_HANA_CONSTEXPR_LAMBDA auto f = [](auto x) {
return hana::chain(hana::sfinae(deref)(x), hana::sfinae(age));
};
struct Person {
unsigned int age;
// ...
};
int main() {
Person john{30};
// Can't dereference a non-pointer.
BOOST_HANA_CONSTANT_CHECK(f(john) == hana::nothing);
// `int` has no member named `age`.
BOOST_HANA_CONSTANT_CHECK(f(1) == hana::nothing);
// All is good.
BOOST_HANA_CONSTEXPR_CHECK(f(&john) == hana::just(30u));
}
constexpr auto boost::hana::flatten

<#include <boost/hana/fwd/flatten.hpp>>

Initial value:
= [](auto&& xs) {
return tag-dispatched;
}

Два уровня монадической структуры распадаются на один уровень. Учитывая монадическое значение, заключенное в два уровня монады,<flatten>удаляет один такой уровень. Реализация<flatten>должна удовлетворять.

flatten(xs) == chain(xs, id)

Для<Sequence>s это просто берет<Sequence>из<Sequence>s и возвращает (не рекурсивно) сплюснутый<Sequence>.

Signature

Для<Monad><M>подпись<flatten>\(\mathtt{flatten} : M(M(T)) \to M(T)\)

Parameters
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)
namespace hana = boost::hana;
static_assert(
hana::flatten(hana::make_tuple(hana::make_tuple(1, 2, 3),
hana::make_tuple(4, 5),
hana::make_tuple(6, 7, 8, 9)))
==
hana::make_tuple(1, 2, 3, 4, 5, 6, 7, 8, 9)
, "");
BOOST_HANA_CONSTANT_CHECK(hana::flatten(hana::nothing) == hana::nothing);
static_assert(hana::flatten(hana::just(hana::just(1))) == hana::just(1), "");
BOOST_HANA_CONSTANT_CHECK(hana::flatten(hana::just(hana::nothing)) == hana::nothing);
int main() { }
constexpr auto boost::hana::monadic_compose

<#include <boost/hana/fwd/monadic_compose.hpp>>

Initial value:
= [](auto&& f, auto&& g) {
return [perfect-capture](auto&& x) -> decltype(auto) {
return hana::chain(forwarded(g)(forwarded(x)), forwarded(f));
};
}
constexpr auto chain
Feed a monadic value into a monadic computation.Given a monadic value and a monadic function...
Definition: chain.hpp:51
constexpr auto capture
Create a function capturing the given variables.
Definition: capture.hpp:45

Состав монадных функций. Учитывая две монадические функции<f>и<g>,<monadic_compose>возвращает новую функцию, эквивалентную композиции<f>с<g>, за исключением того, что результат<g>является<chain>в<f>вместо того, чтобы просто перейти к нему, как с нормальной композицией.<monadic_compose>удовлетворяет.

monadic_compose(f, g)(x) == chain(g(x), f)
Note
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)
namespace hana = boost::hana;
int main() {
BOOST_HANA_CONSTEXPR_LAMBDA auto block = [](auto ...types) {
return [=](auto x) {
return hana::if_(hana::contains(hana::make_tuple(types...), hana::typeid_(x)),
hana::nothing,
hana::just(x)
);
};
};
BOOST_HANA_CONSTEXPR_LAMBDA auto f = block(hana::type_c<double>);
BOOST_HANA_CONSTEXPR_LAMBDA auto g = block(hana::type_c<int>);
BOOST_HANA_CONSTEXPR_LAMBDA auto h = hana::monadic_compose(g, f);
BOOST_HANA_CONSTANT_CHECK(h(1) == hana::nothing); // fails inside g; 1 has type int
BOOST_HANA_CONSTANT_CHECK(h(1.2) == hana::nothing); // fails inside f; 1.2 has type double
BOOST_HANA_CONSTEXPR_CHECK(h('x') == hana::just('x')); // ok; 'x' has type char
}
template<typename M >
constexpr auto boost::hana::tap

<#include <boost/hana/fwd/tap.hpp>>

Initial value:
= [](auto&& f) {
return tag-dispatched;
}

Нажмите внутри монадической цепи. При наличии функции<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)
#include <set>
namespace hana = boost::hana;
int main() {
// We use a sorted container because the order in which the functions
// are called is unspecified.
std::set<int> before, after;
auto xs = hana::make_tuple(1, 2, 3)
| hana::tap<hana::tuple_tag>([&](int x) { before.insert(x); })
| [](auto x) { return hana::make_tuple(x, -x); }
| hana::tap<hana::tuple_tag>([&](int x) { after.insert(x); });
BOOST_HANA_RUNTIME_CHECK(before == std::set<int>{1, 2, 3});
BOOST_HANA_RUNTIME_CHECK(after == std::set<int>{1, -1, 2, -2, 3, -3});
BOOST_HANA_RUNTIME_CHECK(xs == hana::make_tuple(1, -1, 2, -2, 3, -3));
}
constexpr auto boost::hana::then

<#include <boost/hana/fwd/then.hpp>>

Initial value:
= [](auto&& before, auto&& xs) -> decltype(auto) {
return tag-dispatched;
}

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

Parameters
beforeПервый<Monad>в монадической цепи композиции. Результат этой монады игнорируется, но ее эффекты сочетаются с эффектом второй монады.
xsВторая<Monad>в монадической цепи композиции.

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)
namespace hana = boost::hana;
struct undefined { };
static_assert(
hana::then(hana::make_tuple(undefined{}, undefined{}), hana::make_tuple(1, 2, 3))
==
hana::make_tuple(
1, 2, 3,
1, 2, 3
)
, "");
int main() { }

Статья Boost.Hana: Monad раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 20:57:11/0.031712055206299/1