]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) | |
4 | ||
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; | |
11 | ||
12 | ||
13 | namespace wrap_detail { | |
14 | template <typename Datatype, typename X> | |
15 | struct wrapper { | |
16 | X unwrap; | |
17 | using hana_tag = Datatype; | |
18 | }; | |
19 | ||
20 | template <typename Datatype> | |
21 | struct wrap_impl { | |
22 | template <typename X> | |
23 | constexpr auto operator()(X x) const { | |
24 | return wrapper<Datatype, X>{x}; | |
25 | } | |
26 | }; | |
27 | } | |
28 | ||
29 | template <typename Datatype> | |
30 | constexpr wrap_detail::wrap_impl<Datatype> wrap{}; | |
31 | ||
32 | BOOST_HANA_CONSTEXPR_LAMBDA auto unwrap = [](auto x) { | |
33 | return x.unwrap; | |
34 | }; | |
35 | ||
36 | ////////////////////////////////////////////////////////////////////////////// | |
37 | // core | |
38 | ////////////////////////////////////////////////////////////////////////////// | |
39 | template <typename ...> | |
40 | struct not_implemented; | |
41 | ||
42 | ||
43 | ////////////////////////////////////////////////////////////////////////////// | |
44 | // Functor | |
45 | ////////////////////////////////////////////////////////////////////////////// | |
46 | template <typename X, typename F, typename Enable = void> | |
47 | not_implemented<X, F> fmap_impl{}; | |
48 | ||
49 | auto fmap = [](auto x, auto f) { | |
50 | return fmap_impl< | |
51 | hana::tag_of_t<decltype(x)>, | |
52 | hana::tag_of_t<decltype(f)> | |
53 | >(x, f); | |
54 | }; | |
55 | ||
56 | ||
57 | ////////////////////////////////////////////////////////////////////////////// | |
58 | // Applicative | |
59 | ////////////////////////////////////////////////////////////////////////////// | |
60 | template <typename F, typename X, typename Enable = void> | |
61 | not_implemented<F, X> ap_impl{}; | |
62 | ||
63 | auto ap = [](auto f, auto x) { | |
64 | return ap_impl< | |
65 | hana::tag_of_t<decltype(f)>, | |
66 | hana::tag_of_t<decltype(x)> | |
67 | >(f, x); | |
68 | }; | |
69 | ||
70 | template <typename A, typename Enable = void> | |
71 | not_implemented<A> lift_impl{}; | |
72 | ||
73 | template <template <typename> class A> | |
74 | auto lift = [](auto x) { | |
75 | return lift_impl<A<hana::tag_of_t<decltype(x)>>>(x); | |
76 | }; | |
77 | ||
78 | ||
79 | ////////////////////////////////////////////////////////////////////////////// | |
80 | // Function | |
81 | ////////////////////////////////////////////////////////////////////////////// | |
82 | template <typename F, typename X, typename Enable = void> | |
83 | not_implemented<F, X> apply_impl{}; | |
84 | ||
85 | auto apply = [](auto f, auto x) { | |
86 | return apply_impl< | |
87 | hana::tag_of_t<decltype(f)>, | |
88 | hana::tag_of_t<decltype(x)> | |
89 | >(f, x); | |
90 | }; | |
91 | ||
92 | template <typename Domain, typename Codomain> | |
93 | struct Function; | |
94 | ||
95 | template <typename Domain, typename Codomain> | |
96 | auto function = [](auto f) { | |
97 | return wrap<Function<Domain, Codomain>>(f); | |
98 | }; | |
99 | ||
100 | template <typename X, typename Y> | |
101 | auto apply_impl<Function<X, Y>, X> = [](auto f, auto x) { | |
102 | return unwrap(f)(x); | |
103 | }; | |
104 | ||
105 | ||
106 | ////////////////////////////////////////////////////////////////////////////// | |
107 | // List | |
108 | ////////////////////////////////////////////////////////////////////////////// | |
109 | template <typename T> | |
110 | struct List; | |
111 | ||
112 | template <typename T> | |
113 | auto list = [](auto ...xs) { | |
114 | return wrap<List<T>>( | |
115 | [=](auto f) { return f(xs...); } | |
116 | ); | |
117 | }; | |
118 | ||
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)...); | |
123 | }); | |
124 | }; | |
125 | ||
126 | template <typename X> | |
127 | auto lift_impl<List<X>> = [](auto x) { | |
128 | return list<X>(x); | |
129 | }; | |
130 | ||
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)...); | |
135 | }); | |
136 | auto hana_xs = unwrap(xs)(hana::make_tuple); | |
137 | auto hana_result = hana::ap(hana_fs, hana_xs); | |
138 | ||
139 | return hana::unpack(hana_result, list<Y>); | |
140 | }; | |
141 | ||
142 | ||
143 | ////////////////////////////////////////////////////////////////////////////// | |
144 | // Any | |
145 | ////////////////////////////////////////////////////////////////////////////// | |
146 | struct Any; | |
147 | ||
148 | auto any = [](auto x) { | |
149 | return wrap<Any>(x); | |
150 | }; | |
151 | ||
152 | ||
153 | int main() { | |
154 | auto f = function<int, int>([](auto x) { return x + 1; }); | |
155 | auto xs = list<int>(1, 2, 3, 4); | |
156 | fmap(xs, f); | |
157 | ||
158 | lift<List>(2); | |
159 | ap(list<Function<int, int>>(f, f), list<int>(1, 2)); | |
160 | ||
161 | auto g = function<Any, int>([](auto /*x*/) { | |
162 | // We can't do anything with an Any, so there's not much choice here. | |
163 | return 1; | |
164 | }); | |
165 | fmap(list<Any>(any(1), any('2'), any("345")), g); | |
166 | } |