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)
5 #include <boost/hana/lazy.hpp>
7 #include <boost/hana/ap.hpp>
8 #include <boost/hana/assert.hpp>
9 #include <boost/hana/chain.hpp>
10 #include <boost/hana/concept/comparable.hpp>
11 #include <boost/hana/config.hpp>
12 #include <boost/hana/duplicate.hpp>
13 #include <boost/hana/equal.hpp>
14 #include <boost/hana/eval.hpp>
15 #include <boost/hana/extend.hpp>
16 #include <boost/hana/extract.hpp>
17 #include <boost/hana/flatten.hpp>
18 #include <boost/hana/functional/compose.hpp>
19 #include <boost/hana/lift.hpp>
20 #include <boost/hana/transform.hpp>
21 #include <boost/hana/tuple.hpp>
23 #include <laws/applicative.hpp>
24 #include <laws/base.hpp>
25 #include <laws/comonad.hpp>
26 #include <laws/functor.hpp>
27 #include <laws/monad.hpp>
28 #include <support/tracked.hpp>
32 namespace hana
= boost::hana
;
33 using hana::test::ct_eq
;
36 namespace boost
{ namespace hana
{
37 // We provide this instance for unit tests only because it is _so_ much
38 // more convenient, but this instance is too dangerous for general usage.
39 // See the documentation of `hana::lazy` for more info.
41 struct equal_impl
<lazy_tag
, lazy_tag
> {
42 template <typename X
, typename Y
>
43 static constexpr auto apply(X x
, Y y
)
44 { return hana::equal(hana::eval(x
), hana::eval(y
)); }
48 auto invalid
= [](auto x
)
49 { return x
.this_function_must_not_be_instantiated
; };
53 hana::test::_injection
<0> f
{};
55 auto eqs
= hana::make_tuple(
56 hana::make_lazy(ct_eq
<0>{}),
57 hana::make_lazy(ct_eq
<1>{}),
58 hana::make_lazy(ct_eq
<2>{})
60 auto eq_elems
= hana::make_tuple(ct_eq
<0>{}, ct_eq
<1>{}, ct_eq
<1>{});
61 auto nested
= hana::make_tuple(
62 hana::make_lazy(hana::make_lazy(ct_eq
<0>{})),
63 hana::make_lazy(hana::make_lazy(ct_eq
<1>{})),
64 hana::make_lazy(hana::make_lazy(ct_eq
<2>{}))
67 //////////////////////////////////////////////////////////////////////////
69 //////////////////////////////////////////////////////////////////////////
73 BOOST_HANA_CONSTANT_CHECK(hana::equal(
77 BOOST_HANA_CONSTANT_CHECK(hana::equal(
78 hana::make_lazy(f
)(ct_eq
<0>{}),
79 hana::make_lazy(f(ct_eq
<0>{}))
81 BOOST_HANA_CONSTANT_CHECK(hana::equal(
82 hana::make_lazy(f
)(ct_eq
<0>{}, ct_eq
<1>{}),
83 hana::make_lazy(f(ct_eq
<0>{}, ct_eq
<1>{}))
85 BOOST_HANA_CONSTANT_CHECK(hana::equal(
86 hana::make_lazy(f
)(ct_eq
<0>{}, ct_eq
<1>{}, ct_eq
<2>{}),
87 hana::make_lazy(f(ct_eq
<0>{}, ct_eq
<1>{}, ct_eq
<2>{}))
90 // The function is not applied.
91 hana::make_lazy(invalid
)();
92 hana::make_lazy(invalid
)(ct_eq
<0>{});
93 hana::make_lazy(invalid
)(ct_eq
<0>{}, ct_eq
<1>{});
94 hana::make_lazy(invalid
)(ct_eq
<0>{}, ct_eq
<1>{}, ct_eq
<2>{});
99 // With lazy expressions
100 BOOST_HANA_CONSTANT_CHECK(hana::equal(
101 hana::eval(hana::make_lazy(ct_eq
<0>{})),
104 BOOST_HANA_CONSTANT_CHECK(hana::equal(
105 hana::eval(hana::make_lazy(ct_eq
<1>{})),
109 BOOST_HANA_CONSTANT_CHECK(hana::equal(
110 hana::eval(hana::make_lazy(f
)()),
113 BOOST_HANA_CONSTANT_CHECK(hana::equal(
114 hana::eval(hana::make_lazy(f
)(ct_eq
<3>{})),
117 BOOST_HANA_CONSTANT_CHECK(hana::equal(
118 hana::eval(hana::make_lazy(f
)(ct_eq
<3>{}, ct_eq
<4>{})),
119 f(ct_eq
<3>{}, ct_eq
<4>{})
122 // Should call a nullary function
123 BOOST_HANA_CONSTANT_CHECK(hana::equal(
124 hana::eval([]{ return ct_eq
<3>{}; }),
128 // Should call a unary function with hana::id.
129 BOOST_HANA_CONSTANT_CHECK(hana::equal(
130 hana::eval([](auto _
) { return _(ct_eq
<3>{}); }),
134 // For overloaded function objects that are both nullary and unary,
135 // the nullary overload should be preferred.
136 BOOST_HANA_CONSTANT_CHECK(hana::equal(
142 // Make sure this does not move from a destroyed object, as that
143 // used to be the case.
145 auto x
= hana::flatten(hana::make_lazy(hana::make_lazy(Tracked
{1})));
146 auto z
= hana::eval(x
); (void)z
;
149 // In some cases where a type has a constructor that is way too
150 // general, copying a lazy value holding an object of that type
151 // could trigger the instantiation of that constructor. If that
152 // constructor was ill-formed, the compilation would fail. We
153 // make sure this does not happen.
156 auto expr
= hana::make_lazy(hana::test::trap_construct
{});
157 auto implicit_copy
= expr
; (void)implicit_copy
;
158 decltype(expr
) explicit_copy(expr
); (void)explicit_copy
;
162 auto expr
= hana::make_lazy(hana::test::trap_construct
{})();
163 auto implicit_copy
= expr
; (void)implicit_copy
;
164 decltype(expr
) explicit_copy(expr
); (void)explicit_copy
;
169 //////////////////////////////////////////////////////////////////////////
171 //////////////////////////////////////////////////////////////////////////
175 BOOST_HANA_CONSTANT_CHECK(hana::equal(
176 hana::transform(hana::make_lazy(ct_eq
<0>{}), f
),
177 hana::make_lazy(f(ct_eq
<0>{}))
182 hana::test::TestFunctor
<hana::lazy_tag
>{eqs
, eq_elems
};
185 //////////////////////////////////////////////////////////////////////////
187 //////////////////////////////////////////////////////////////////////////
191 BOOST_HANA_CONSTANT_CHECK(hana::equal(
192 hana::ap(hana::make_lazy(f
), hana::make_lazy(ct_eq
<0>{})),
193 hana::make_lazy(f(ct_eq
<0>{}))
195 BOOST_HANA_CONSTANT_CHECK(hana::equal(
196 hana::ap(hana::make_lazy(f
), hana::make_lazy(ct_eq
<0>{}), hana::make_lazy(ct_eq
<1>{})),
197 hana::make_lazy(f(ct_eq
<0>{}, ct_eq
<1>{}))
199 BOOST_HANA_CONSTANT_CHECK(hana::equal(
200 hana::ap(hana::make_lazy(f
), hana::make_lazy(ct_eq
<0>{}), hana::make_lazy(ct_eq
<1>{}), hana::make_lazy(ct_eq
<2>{})),
201 hana::make_lazy(f(ct_eq
<0>{}, ct_eq
<1>{}, ct_eq
<2>{}))
204 // The function is not applied.
205 hana::ap(hana::make_lazy(invalid
), hana::make_lazy(ct_eq
<0>{}));
206 hana::ap(hana::make_lazy(invalid
), hana::make_lazy(ct_eq
<0>{}), hana::make_lazy(ct_eq
<1>{}));
207 hana::ap(hana::make_lazy(invalid
), hana::make_lazy(ct_eq
<0>{}), hana::make_lazy(ct_eq
<1>{}), hana::make_lazy(ct_eq
<2>{}));
212 BOOST_HANA_CONSTANT_CHECK(hana::equal(
213 hana::lift
<hana::lazy_tag
>(ct_eq
<0>{}),
214 hana::make_lazy(ct_eq
<0>{})
216 BOOST_HANA_CONSTANT_CHECK(hana::equal(
217 hana::lift
<hana::lazy_tag
>(ct_eq
<1>{}),
218 hana::make_lazy(ct_eq
<1>{})
223 hana::test::TestApplicative
<hana::lazy_tag
>{eqs
};
226 //////////////////////////////////////////////////////////////////////////
228 //////////////////////////////////////////////////////////////////////////
230 auto f_
= hana::compose(hana::make_lazy
, f
);
234 BOOST_HANA_CONSTANT_CHECK(hana::equal(
235 hana::chain(hana::make_lazy(ct_eq
<0>{}), f_
),
238 BOOST_HANA_CONSTANT_CHECK(hana::equal(
239 hana::chain(hana::make_lazy(ct_eq
<1>{}), f_
),
243 BOOST_HANA_CONSTANT_CHECK(hana::equal(
244 hana::make_lazy(ct_eq
<1>{}) | f_
,
251 BOOST_HANA_CONSTANT_CHECK(hana::equal(
252 hana::flatten(hana::make_lazy(hana::make_lazy(ct_eq
<0>{}))),
253 hana::make_lazy(ct_eq
<0>{})
255 BOOST_HANA_CONSTANT_CHECK(hana::equal(
256 hana::flatten(hana::make_lazy(hana::make_lazy(ct_eq
<1>{}))),
257 hana::make_lazy(ct_eq
<1>{})
259 BOOST_HANA_CONSTANT_CHECK(hana::equal(
260 hana::flatten(hana::make_lazy(hana::make_lazy(hana::make_lazy(ct_eq
<1>{})))),
261 hana::make_lazy(hana::make_lazy(ct_eq
<1>{}))
266 hana::test::TestMonad
<hana::lazy_tag
>{eqs
, nested
};
269 //////////////////////////////////////////////////////////////////////////
271 //////////////////////////////////////////////////////////////////////////
275 BOOST_HANA_CONSTANT_CHECK(hana::equal(
276 hana::extract(hana::make_lazy(ct_eq
<4>{})),
283 BOOST_HANA_CONSTANT_CHECK(hana::equal(
284 hana::duplicate(hana::make_lazy(ct_eq
<4>{})),
285 hana::make_lazy(hana::make_lazy(ct_eq
<4>{}))
291 BOOST_HANA_CONSTANT_CHECK(hana::equal(
292 hana::extend(hana::make_lazy(ct_eq
<4>{}), f
),
293 hana::make_lazy(f(hana::make_lazy(ct_eq
<4>{})))
298 hana::test::TestComonad
<hana::lazy_tag
>{eqs
};
301 //////////////////////////////////////////////////////////////////////////
302 // Make sure the monadic chain is evaluated in the right order.
303 //////////////////////////////////////////////////////////////////////////
305 std::array
<bool, 3> executed
= {{false, false, false}};
308 std::cout
<< "creating the monadic chain...\n";
309 auto chain
= hana::make_lazy(dummy
)
311 std::cout
<< "executing the first computation...\n";
313 BOOST_HANA_RUNTIME_CHECK(
314 executed
== std::array
<bool, 3>{{true, false, false}}
316 return hana::make_lazy(dummy
);
319 std::cout
<< "executing the second computation...\n";
321 BOOST_HANA_RUNTIME_CHECK(
322 executed
== std::array
<bool, 3>{{true, true, false}}
324 return hana::make_lazy(dummy
);
327 std::cout
<< "executing the third computation...\n";
329 BOOST_HANA_RUNTIME_CHECK(
330 executed
== std::array
<bool, 3>{{true, true, true}}
332 return hana::make_lazy(dummy
);
335 BOOST_HANA_RUNTIME_CHECK(
336 executed
== std::array
<bool, 3>{{false, false, false}}
339 std::cout
<< "evaluating the chain...\n";