1 // Copyright Louis Dionne 2013-2016
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/ap.hpp>
6 #include <boost/hana/config.hpp>
7 #include <boost/hana/core/make.hpp>
8 #include <boost/hana/core/tag_of.hpp>
9 #include <boost/hana/tuple.hpp>
10 namespace hana
= boost::hana
;
13 namespace wrap_detail
{
14 template <typename Datatype
, typename X
>
17 using hana_tag
= Datatype
;
20 template <typename Datatype
>
23 constexpr auto operator()(X x
) const {
24 return wrapper
<Datatype
, X
>{x
};
29 template <typename Datatype
>
30 constexpr wrap_detail::wrap_impl
<Datatype
> wrap
{};
32 BOOST_HANA_CONSTEXPR_LAMBDA
auto unwrap
= [](auto x
) {
36 //////////////////////////////////////////////////////////////////////////////
38 //////////////////////////////////////////////////////////////////////////////
39 template <typename
...>
40 struct not_implemented
;
43 //////////////////////////////////////////////////////////////////////////////
45 //////////////////////////////////////////////////////////////////////////////
46 template <typename X
, typename F
, typename Enable
= void>
47 not_implemented
<X
, F
> fmap_impl
{};
49 auto fmap
= [](auto x
, auto f
) {
51 hana::tag_of_t
<decltype(x
)>,
52 hana::tag_of_t
<decltype(f
)>
57 //////////////////////////////////////////////////////////////////////////////
59 //////////////////////////////////////////////////////////////////////////////
60 template <typename F
, typename X
, typename Enable
= void>
61 not_implemented
<F
, X
> ap_impl
{};
63 auto ap
= [](auto f
, auto x
) {
65 hana::tag_of_t
<decltype(f
)>,
66 hana::tag_of_t
<decltype(x
)>
70 template <typename A
, typename Enable
= void>
71 not_implemented
<A
> lift_impl
{};
73 template <template <typename
> class A
>
74 auto lift
= [](auto x
) {
75 return lift_impl
<A
<hana::tag_of_t
<decltype(x
)>>>(x
);
79 //////////////////////////////////////////////////////////////////////////////
81 //////////////////////////////////////////////////////////////////////////////
82 template <typename F
, typename X
, typename Enable
= void>
83 not_implemented
<F
, X
> apply_impl
{};
85 auto apply
= [](auto f
, auto x
) {
87 hana::tag_of_t
<decltype(f
)>,
88 hana::tag_of_t
<decltype(x
)>
92 template <typename Domain
, typename Codomain
>
95 template <typename Domain
, typename Codomain
>
96 auto function
= [](auto f
) {
97 return wrap
<Function
<Domain
, Codomain
>>(f
);
100 template <typename X
, typename Y
>
101 auto apply_impl
<Function
<X
, Y
>, X
> = [](auto f
, auto x
) {
106 //////////////////////////////////////////////////////////////////////////////
108 //////////////////////////////////////////////////////////////////////////////
109 template <typename T
>
112 template <typename T
>
113 auto list
= [](auto ...xs
) {
114 return wrap
<List
<T
>>(
115 [=](auto f
) { return f(xs
...); }
119 template <typename X
, typename Y
>
120 auto fmap_impl
<List
<X
>, Function
<X
, Y
>> = [](auto xs
, auto f
) {
121 return unwrap(xs
)([=](auto ...xs
) {
122 return list
<Y
>(apply(f
, xs
)...);
126 template <typename X
>
127 auto lift_impl
<List
<X
>> = [](auto x
) {
131 template <typename X
, typename Y
>
132 auto ap_impl
<List
<Function
<X
, Y
>>, List
<X
>> = [](auto fs
, auto xs
) {
133 auto hana_fs
= unwrap(fs
)([](auto ...fs
) {
134 return hana::make_tuple(hana::partial(apply
, fs
)...);
136 auto hana_xs
= unwrap(xs
)(hana::make_tuple
);
137 auto hana_result
= hana::ap(hana_fs
, hana_xs
);
139 return hana::unpack(hana_result
, list
<Y
>);
143 //////////////////////////////////////////////////////////////////////////////
145 //////////////////////////////////////////////////////////////////////////////
148 auto any
= [](auto x
) {
154 auto f
= function
<int, int>([](auto x
) { return x
+ 1; });
155 auto xs
= list
<int>(1, 2, 3, 4);
159 ap(list
<Function
<int, int>>(f
, f
), list
<int>(1, 2));
161 auto g
= function
<Any
, int>([](auto /*x*/) {
162 // We can't do anything with an Any, so there's not much choice here.
165 fmap(list
<Any
>(any(1), any('2'), any("345")), g
);