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 5 #ifndef BOOST_HANA_TEST_LAWS_APPLICATIVE_HPP 6 #define BOOST_HANA_TEST_LAWS_APPLICATIVE_HPP 7 8 #include <boost/hana/ap.hpp> 9 #include <boost/hana/assert.hpp> 10 #include <boost/hana/bool.hpp> 11 #include <boost/hana/concept/applicative.hpp> 12 #include <boost/hana/concept/comparable.hpp> 13 #include <boost/hana/core/make.hpp> 14 #include <boost/hana/core/when.hpp> 15 #include <boost/hana/equal.hpp> 16 #include <boost/hana/for_each.hpp> 17 #include <boost/hana/functional/capture.hpp> 18 #include <boost/hana/functional/compose.hpp> 19 #include <boost/hana/functional/curry.hpp> 20 #include <boost/hana/functional/id.hpp> 21 #include <boost/hana/functional/placeholder.hpp> 22 #include <boost/hana/integral_constant.hpp> 23 #include <boost/hana/lift.hpp> 24 #include <boost/hana/take_front.hpp> 25 #include <boost/hana/transform.hpp> 26 27 #include <laws/base.hpp> 28 29 30 namespace boost { namespace hana { namespace test { 31 template <typename F, typename = when<true>> 32 struct TestApplicative : TestApplicative<F, laws> { 33 using TestApplicative<F, laws>::TestApplicative; 34 }; 35 36 template <typename F> 37 struct TestApplicative<F, laws> { 38 template <typename Applicatives> TestApplicativeboost::hana::test::TestApplicative39 TestApplicative(Applicatives applicatives) { 40 hana::for_each(applicatives, [](auto a) { 41 static_assert(Applicative<decltype(a)>{}, ""); 42 }); 43 44 auto functions1 = hana::take_front( 45 hana::transform(applicatives, [](auto xs) { 46 return hana::transform(xs, hana::curry<2>(test::_injection<0>{})); 47 }), hana::int_c<3>); 48 49 auto functions2 = hana::take_front( 50 hana::transform(applicatives, [](auto xs) { 51 return hana::transform(xs, hana::curry<2>(test::_injection<1>{})); 52 }), hana::int_c<3>); 53 54 // identity 55 { 56 hana::for_each(applicatives, [](auto xs) { 57 BOOST_HANA_CHECK(hana::equal( 58 hana::ap(hana::lift<F>(hana::id), xs), 59 xs 60 )); 61 }); 62 } 63 64 // composition 65 { 66 hana::for_each(applicatives, hana::capture(functions1, functions2)( 67 [](auto functions1, auto functions2, auto xs) { 68 hana::for_each(functions1, hana::capture(functions2, xs)( 69 [](auto functions2, auto xs, auto fs) { 70 hana::for_each(functions2, hana::capture(xs, fs)( 71 [](auto xs, auto fs, auto gs) { 72 BOOST_HANA_CHECK(hana::equal( 73 hana::ap(hana::ap(hana::lift<F>(compose), fs, gs), xs), 74 hana::ap(fs, hana::ap(gs, xs)) 75 )); 76 }));}));})); 77 } 78 79 // homomorphism 80 { 81 test::_injection<0> f{}; 82 test::ct_eq<3> x{}; 83 BOOST_HANA_CONSTANT_CHECK(hana::equal( 84 hana::ap(hana::lift<F>(f), hana::lift<F>(x)), 85 hana::lift<F>(f(x)) 86 )); 87 } 88 89 // interchange 90 { 91 hana::for_each(functions1, [](auto fs) { 92 test::ct_eq<4> x{}; 93 BOOST_HANA_CHECK(hana::equal( 94 hana::ap(fs, hana::lift<F>(x)), 95 hana::ap(hana::lift<F>(hana::_(x)), fs) 96 )); 97 }); 98 } 99 100 // definition of transform 101 { 102 hana::for_each(applicatives, [](auto xs) { 103 test::_injection<0> f{}; 104 BOOST_HANA_CHECK(hana::equal( 105 hana::transform(xs, f), 106 hana::ap(hana::lift<F>(f), xs) 107 )); 108 }); 109 } 110 } 111 }; 112 113 template <typename S> 114 struct TestApplicative<S, when<Sequence<S>::value>> 115 : TestApplicative<S, laws> 116 { 117 template <typename Applicatives> TestApplicativeboost::hana::test::TestApplicative118 TestApplicative(Applicatives applicatives) 119 : TestApplicative<S, laws>{applicatives} 120 { 121 _injection<0> f{}; 122 _injection<1> g{}; 123 using test::ct_eq; 124 constexpr auto list = make<S>; 125 126 ////////////////////////////////////////////////////////////////// 127 // ap 128 ////////////////////////////////////////////////////////////////// 129 BOOST_HANA_CONSTANT_CHECK(hana::equal( 130 hana::ap(list(), list()), 131 list() 132 )); 133 BOOST_HANA_CONSTANT_CHECK(hana::equal( 134 hana::ap(list(), list(ct_eq<0>{})), 135 list() 136 )); 137 BOOST_HANA_CONSTANT_CHECK(hana::equal( 138 hana::ap(list(), list(ct_eq<0>{}, ct_eq<1>{})), 139 list() 140 )); 141 BOOST_HANA_CONSTANT_CHECK(hana::equal( 142 hana::ap(list(), list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})), 143 list() 144 )); 145 146 BOOST_HANA_CONSTANT_CHECK(hana::equal( 147 hana::ap(list(f), list()), 148 list() 149 )); 150 BOOST_HANA_CONSTANT_CHECK(hana::equal( 151 hana::ap(list(f), list(ct_eq<0>{})), 152 list(f(ct_eq<0>{})) 153 )); 154 BOOST_HANA_CONSTANT_CHECK(hana::equal( 155 hana::ap(list(f), list(ct_eq<0>{}, ct_eq<1>{})), 156 list(f(ct_eq<0>{}), f(ct_eq<1>{})) 157 )); 158 BOOST_HANA_CONSTANT_CHECK(hana::equal( 159 hana::ap(list(f), list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})), 160 list(f(ct_eq<0>{}), f(ct_eq<1>{}), f(ct_eq<2>{})) 161 )); 162 163 BOOST_HANA_CONSTANT_CHECK(hana::equal( 164 hana::ap(list(f, g), list()), 165 list() 166 )); 167 BOOST_HANA_CONSTANT_CHECK(hana::equal( 168 hana::ap(list(f, g), list(ct_eq<0>{})), 169 list(f(ct_eq<0>{}), g(ct_eq<0>{})) 170 )); 171 BOOST_HANA_CONSTANT_CHECK(hana::equal( 172 hana::ap(list(f, g), list(ct_eq<0>{}, ct_eq<1>{})), 173 list(f(ct_eq<0>{}), f(ct_eq<1>{}), g(ct_eq<0>{}), g(ct_eq<1>{})) 174 )); 175 BOOST_HANA_CONSTANT_CHECK(hana::equal( 176 hana::ap(list(f, g), list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})), 177 list(f(ct_eq<0>{}), f(ct_eq<1>{}), f(ct_eq<2>{}), 178 g(ct_eq<0>{}), g(ct_eq<1>{}), g(ct_eq<2>{})) 179 )); 180 181 ////////////////////////////////////////////////////////////////// 182 // lift 183 ////////////////////////////////////////////////////////////////// 184 BOOST_HANA_CONSTANT_CHECK(hana::equal( 185 lift<S>(ct_eq<0>{}), 186 list(ct_eq<0>{}) 187 )); 188 BOOST_HANA_CONSTANT_CHECK(hana::equal( 189 lift<S>(ct_eq<1>{}), 190 list(ct_eq<1>{}) 191 )); 192 } 193 }; 194 }}} // end namespace boost::hana::test 195 196 #endif // !BOOST_HANA_TEST_LAWS_APPLICATIVE_HPP 197