monad.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #ifndef BOOST_HANA_TEST_LAWS_MONAD_HPP
  5. #define BOOST_HANA_TEST_LAWS_MONAD_HPP
  6. #include <boost/hana/assert.hpp>
  7. #include <boost/hana/bool.hpp>
  8. #include <boost/hana/chain.hpp>
  9. #include <boost/hana/concept/comparable.hpp>
  10. #include <boost/hana/concept/monad.hpp>
  11. #include <boost/hana/concept/sequence.hpp>
  12. #include <boost/hana/core/make.hpp>
  13. #include <boost/hana/core/when.hpp>
  14. #include <boost/hana/equal.hpp>
  15. #include <boost/hana/flatten.hpp>
  16. #include <boost/hana/for_each.hpp>
  17. #include <boost/hana/functional/compose.hpp>
  18. #include <boost/hana/functional/id.hpp>
  19. #include <boost/hana/lift.hpp>
  20. #include <boost/hana/monadic_compose.hpp>
  21. #include <boost/hana/transform.hpp>
  22. #include <laws/base.hpp>
  23. namespace boost { namespace hana { namespace test {
  24. template <typename M, typename = when<true>>
  25. struct TestMonad : TestMonad<M, laws> {
  26. using TestMonad<M, laws>::TestMonad;
  27. };
  28. template <typename M>
  29. struct TestMonad<M, laws> {
  30. // Xs are Monads over something
  31. // XXs are Monads over Monads over something
  32. template <typename Xs, typename XXs>
  33. TestMonad(Xs xs, XXs xxs) {
  34. hana::for_each(xs, [](auto m) {
  35. static_assert(Monad<decltype(m)>{}, "");
  36. auto f = hana::compose(lift<M>, test::_injection<0>{});
  37. auto g = hana::compose(lift<M>, test::_injection<1>{});
  38. auto h = hana::compose(lift<M>, test::_injection<2>{});
  39. auto x = test::ct_eq<0>{};
  40. //////////////////////////////////////////////////////////////
  41. // Laws formulated with `monadic_compose`
  42. //////////////////////////////////////////////////////////////
  43. // associativity
  44. BOOST_HANA_CHECK(hana::equal(
  45. hana::monadic_compose(h, hana::monadic_compose(g, f))(x),
  46. hana::monadic_compose(hana::monadic_compose(h, g), f)(x)
  47. ));
  48. // left identity
  49. BOOST_HANA_CHECK(hana::equal(
  50. hana::monadic_compose(lift<M>, f)(x),
  51. f(x)
  52. ));
  53. // right identity
  54. BOOST_HANA_CHECK(hana::equal(
  55. hana::monadic_compose(f, lift<M>)(x),
  56. f(x)
  57. ));
  58. //////////////////////////////////////////////////////////////
  59. // Laws formulated with `chain`
  60. //
  61. // This just provides us with some additional cross-checking,
  62. // but the documentation does not mention those.
  63. //////////////////////////////////////////////////////////////
  64. BOOST_HANA_CHECK(hana::equal(
  65. hana::chain(hana::lift<M>(x), f),
  66. f(x)
  67. ));
  68. BOOST_HANA_CHECK(hana::equal(
  69. hana::chain(m, lift<M>),
  70. m
  71. ));
  72. BOOST_HANA_CHECK(hana::equal(
  73. hana::chain(m, [f, g](auto x) {
  74. return hana::chain(f(x), g);
  75. }),
  76. hana::chain(hana::chain(m, f), g)
  77. ));
  78. BOOST_HANA_CHECK(hana::equal(
  79. hana::transform(m, f),
  80. hana::chain(m, hana::compose(lift<M>, f))
  81. ));
  82. //////////////////////////////////////////////////////////////
  83. // Consistency of method definitions
  84. //////////////////////////////////////////////////////////////
  85. // consistency of `chain`
  86. BOOST_HANA_CHECK(hana::equal(
  87. hana::chain(m, f),
  88. hana::flatten(hana::transform(m, f))
  89. ));
  90. // consistency of `monadic_compose`
  91. BOOST_HANA_CHECK(hana::equal(
  92. hana::monadic_compose(f, g)(x),
  93. hana::chain(g(x), f)
  94. ));
  95. });
  96. // consistency of `flatten`
  97. hana::for_each(xxs, [](auto mm) {
  98. BOOST_HANA_CHECK(hana::equal(
  99. hana::flatten(mm),
  100. hana::chain(mm, hana::id)
  101. ));
  102. });
  103. }
  104. };
  105. template <typename S>
  106. struct TestMonad<S, when<Sequence<S>::value>>
  107. : TestMonad<S, laws>
  108. {
  109. template <typename Xs, typename XXs>
  110. TestMonad(Xs xs, XXs xxs)
  111. : TestMonad<S, laws>{xs, xxs}
  112. {
  113. constexpr auto list = make<S>;
  114. //////////////////////////////////////////////////////////////////
  115. // flatten
  116. //////////////////////////////////////////////////////////////////
  117. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  118. hana::flatten(list(list(), list())),
  119. list()
  120. ));
  121. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  122. hana::flatten(list(list(ct_eq<0>{}), list())),
  123. list(ct_eq<0>{})
  124. ));
  125. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  126. hana::flatten(list(list(), list(ct_eq<0>{}))),
  127. list(ct_eq<0>{})
  128. ));
  129. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  130. hana::flatten(list(list(ct_eq<0>{}), list(ct_eq<1>{}))),
  131. list(ct_eq<0>{}, ct_eq<1>{})
  132. ));
  133. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  134. hana::flatten(list(
  135. list(ct_eq<0>{}, ct_eq<1>{}),
  136. list(),
  137. list(ct_eq<2>{}, ct_eq<3>{}),
  138. list(ct_eq<4>{})
  139. )),
  140. list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{})
  141. ));
  142. // just make sure we don't double move; this happened in hana::tuple
  143. hana::flatten(list(list(Tracked{1}, Tracked{2})));
  144. //////////////////////////////////////////////////////////////////
  145. // chain
  146. //////////////////////////////////////////////////////////////////
  147. {
  148. test::_injection<0> f{};
  149. auto g = hana::compose(list, f);
  150. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  151. hana::chain(list(), g),
  152. list()
  153. ));
  154. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  155. hana::chain(list(ct_eq<1>{}), g),
  156. list(f(ct_eq<1>{}))
  157. ));
  158. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  159. hana::chain(list(ct_eq<1>{}, ct_eq<2>{}), g),
  160. list(f(ct_eq<1>{}), f(ct_eq<2>{}))
  161. ));
  162. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  163. hana::chain(list(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}), g),
  164. list(f(ct_eq<1>{}), f(ct_eq<2>{}), f(ct_eq<3>{}))
  165. ));
  166. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  167. hana::chain(list(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}), g),
  168. list(f(ct_eq<1>{}), f(ct_eq<2>{}), f(ct_eq<3>{}), f(ct_eq<4>{}))
  169. ));
  170. }
  171. //////////////////////////////////////////////////////////////////
  172. // monadic_compose
  173. //////////////////////////////////////////////////////////////////
  174. {
  175. test::_injection<0> f{};
  176. test::_injection<1> g{};
  177. auto mf = [=](auto x) { return list(f(x), f(f(x))); };
  178. auto mg = [=](auto x) { return list(g(x), g(g(x))); };
  179. auto x = test::ct_eq<0>{};
  180. BOOST_HANA_CHECK(hana::equal(
  181. hana::monadic_compose(mf, mg)(x),
  182. list(f(g(x)), f(f(g(x))), f(g(g(x))), f(f(g(g(x)))))
  183. ));
  184. }
  185. }
  186. };
  187. }}} // end namespace boost::hana::test
  188. #endif // !BOOST_HANA_TEST_LAWS_MONAD_HPP