diff options
Diffstat (limited to 'src/boost/libs/hana/test/_include/laws/monad.hpp')
-rw-r--r-- | src/boost/libs/hana/test/_include/laws/monad.hpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/boost/libs/hana/test/_include/laws/monad.hpp b/src/boost/libs/hana/test/_include/laws/monad.hpp new file mode 100644 index 000000000..25a23d417 --- /dev/null +++ b/src/boost/libs/hana/test/_include/laws/monad.hpp @@ -0,0 +1,222 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_HANA_TEST_LAWS_MONAD_HPP +#define BOOST_HANA_TEST_LAWS_MONAD_HPP + +#include <boost/hana/assert.hpp> +#include <boost/hana/bool.hpp> +#include <boost/hana/chain.hpp> +#include <boost/hana/concept/comparable.hpp> +#include <boost/hana/concept/monad.hpp> +#include <boost/hana/concept/sequence.hpp> +#include <boost/hana/core/make.hpp> +#include <boost/hana/core/when.hpp> +#include <boost/hana/equal.hpp> +#include <boost/hana/flatten.hpp> +#include <boost/hana/for_each.hpp> +#include <boost/hana/functional/compose.hpp> +#include <boost/hana/functional/id.hpp> +#include <boost/hana/lift.hpp> +#include <boost/hana/monadic_compose.hpp> +#include <boost/hana/transform.hpp> + +#include <laws/base.hpp> + + +namespace boost { namespace hana { namespace test { + template <typename M, typename = when<true>> + struct TestMonad : TestMonad<M, laws> { + using TestMonad<M, laws>::TestMonad; + }; + + template <typename M> + struct TestMonad<M, laws> { + // Xs are Monads over something + // XXs are Monads over Monads over something + template <typename Xs, typename XXs> + TestMonad(Xs xs, XXs xxs) { + hana::for_each(xs, [](auto m) { + static_assert(Monad<decltype(m)>{}, ""); + + auto f = hana::compose(lift<M>, test::_injection<0>{}); + auto g = hana::compose(lift<M>, test::_injection<1>{}); + auto h = hana::compose(lift<M>, test::_injection<2>{}); + auto x = test::ct_eq<0>{}; + + ////////////////////////////////////////////////////////////// + // Laws formulated with `monadic_compose` + ////////////////////////////////////////////////////////////// + // associativity + BOOST_HANA_CHECK(hana::equal( + hana::monadic_compose(h, hana::monadic_compose(g, f))(x), + hana::monadic_compose(hana::monadic_compose(h, g), f)(x) + )); + + // left identity + BOOST_HANA_CHECK(hana::equal( + hana::monadic_compose(lift<M>, f)(x), + f(x) + )); + + // right identity + BOOST_HANA_CHECK(hana::equal( + hana::monadic_compose(f, lift<M>)(x), + f(x) + )); + + ////////////////////////////////////////////////////////////// + // Laws formulated with `chain` + // + // This just provides us with some additional cross-checking, + // but the documentation does not mention those. + ////////////////////////////////////////////////////////////// + BOOST_HANA_CHECK(hana::equal( + hana::chain(hana::lift<M>(x), f), + f(x) + )); + + BOOST_HANA_CHECK(hana::equal( + hana::chain(m, lift<M>), + m + )); + + BOOST_HANA_CHECK(hana::equal( + hana::chain(m, [f, g](auto x) { + return hana::chain(f(x), g); + }), + hana::chain(hana::chain(m, f), g) + )); + + BOOST_HANA_CHECK(hana::equal( + hana::transform(m, f), + hana::chain(m, hana::compose(lift<M>, f)) + )); + + ////////////////////////////////////////////////////////////// + // Consistency of method definitions + ////////////////////////////////////////////////////////////// + // consistency of `chain` + BOOST_HANA_CHECK(hana::equal( + hana::chain(m, f), + hana::flatten(hana::transform(m, f)) + )); + + // consistency of `monadic_compose` + BOOST_HANA_CHECK(hana::equal( + hana::monadic_compose(f, g)(x), + hana::chain(g(x), f) + )); + }); + + // consistency of `flatten` + hana::for_each(xxs, [](auto mm) { + BOOST_HANA_CHECK(hana::equal( + hana::flatten(mm), + hana::chain(mm, hana::id) + )); + }); + } + }; + + template <typename S> + struct TestMonad<S, when<Sequence<S>::value>> + : TestMonad<S, laws> + { + template <typename Xs, typename XXs> + TestMonad(Xs xs, XXs xxs) + : TestMonad<S, laws>{xs, xxs} + { + constexpr auto list = make<S>; + + ////////////////////////////////////////////////////////////////// + // flatten + ////////////////////////////////////////////////////////////////// + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::flatten(list(list(), list())), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::flatten(list(list(ct_eq<0>{}), list())), + list(ct_eq<0>{}) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::flatten(list(list(), list(ct_eq<0>{}))), + list(ct_eq<0>{}) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::flatten(list(list(ct_eq<0>{}), list(ct_eq<1>{}))), + list(ct_eq<0>{}, ct_eq<1>{}) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::flatten(list( + list(ct_eq<0>{}, ct_eq<1>{}), + list(), + list(ct_eq<2>{}, ct_eq<3>{}), + list(ct_eq<4>{}) + )), + list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}) + )); + + // just make sure we don't double move; this happened in hana::tuple + hana::flatten(list(list(Tracked{1}, Tracked{2}))); + + ////////////////////////////////////////////////////////////////// + // chain + ////////////////////////////////////////////////////////////////// + { + test::_injection<0> f{}; + auto g = hana::compose(list, f); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::chain(list(), g), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::chain(list(ct_eq<1>{}), g), + list(f(ct_eq<1>{})) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::chain(list(ct_eq<1>{}, ct_eq<2>{}), g), + list(f(ct_eq<1>{}), f(ct_eq<2>{})) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::chain(list(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}), g), + list(f(ct_eq<1>{}), f(ct_eq<2>{}), f(ct_eq<3>{})) + )); + + BOOST_HANA_CONSTANT_CHECK(hana::equal( + hana::chain(list(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}), g), + list(f(ct_eq<1>{}), f(ct_eq<2>{}), f(ct_eq<3>{}), f(ct_eq<4>{})) + )); + } + + ////////////////////////////////////////////////////////////////// + // monadic_compose + ////////////////////////////////////////////////////////////////// + { + test::_injection<0> f{}; + test::_injection<1> g{}; + + auto mf = [=](auto x) { return list(f(x), f(f(x))); }; + auto mg = [=](auto x) { return list(g(x), g(g(x))); }; + + auto x = test::ct_eq<0>{}; + BOOST_HANA_CHECK(hana::equal( + hana::monadic_compose(mf, mg)(x), + list(f(g(x)), f(f(g(x))), f(g(g(x))), f(f(g(g(x))))) + )); + } + } + }; +}}} // end namespace boost::hana::test + +#endif // !BOOST_HANA_TEST_LAWS_MONAD_HPP |