mpc
Haskell-like feature supports in C++
stateT.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <functional> // std::invoke
13#include <mpc/prelude/fst.hpp>
14
15// clang-format off
16
17namespace mpc {
18 // StateT
19 // https://hackage.haskell.org/package/transformers-0.6.0.2/docs/Control-Monad-Trans-State-Lazy.html
20 // [x] StateT
21 // [x] is_StateT
22 // [x] make_StateT
23 // [x] run_StateT
24 // [x] StateT_state_t
25 // [x] StateT_monad_t
26
28 template <class S, monad M>
29 struct StateT : Identity<mpc::function<M(S)>> {
31 using state_type = S;
32 using monad_type = M;
33 };
34
35 // is_StateT
36 namespace detail {
37 template <class>
38 struct is_StateT_impl : std::false_type {};
39
40 template <class S, monad M>
41 struct is_StateT_impl<StateT<S, M>> : std::true_type {};
42 } // namespace detail
43
44 template <class T>
45 concept is_StateT = detail::is_StateT_impl<std::remove_cvref_t<T>>::value;
46
47 template <is_StateT ST>
48 using StateT_state_t = typename std::remove_cvref_t<ST>::state_type;
49
50 template <is_StateT ST>
51 using StateT_monad_t = typename std::remove_cvref_t<ST>::monad_type;
52
53 template <is_StateT ST>
54 using eval_StateT_t = decltype(mpc::fmap(fst, std::declval<StateT_monad_t<ST>>()));
55
56 template <class S, monad M>
57 struct holding<StateT<S, M>> : holding<std::remove_cvref_t<eval_StateT_t<StateT<S, M>>>> {};
58
59 // make_StateT, run_StateT
60 namespace detail {
61 template <class S>
63 using state_type = std::decay_t<S>;
64
65 template <class Fn>
66 requires std::invocable<Fn&, state_type> and monad<std::invoke_result_t<Fn&, state_type>>
67 constexpr auto operator()(Fn&& f) const {
68 using M = std::invoke_result_t<Fn&, state_type>;
69 return StateT<state_type, M>(std::forward<Fn>(f));
70 }
71 };
72
74 template <is_StateT ST>
75 constexpr auto operator()(ST&& x) const noexcept -> decltype(*std::forward<ST>(x)) {
76 return *std::forward<ST>(x);
77 }
78 };
79 } // namespace detail
80
81 inline namespace cpo {
82 template <class S>
83 inline constexpr partial<detail::make_StateT_op<S>> make_StateT{};
84
85 inline constexpr partial<detail::run_StateT_op> run_StateT{};
86 } // namespace cpo
87
88 // instances:
89 // [x] functor
90 // [x] monad
91 // [x] applicative
92 // [x] alternative
93 // [x] monad_trans
94
99 template <class S, monad M>
100 struct monad_traits<StateT<S, M>> {
102 struct bind_op {
103 struct nested_closure {
104 template <class Fn, class U>
105 constexpr auto operator()(Fn&& f, U&& u) const
106 noexcept(noexcept(run_StateT % std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))) % snd(std::forward<U>(u))))
107 -> decltype( run_StateT % std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))) % snd(std::forward<U>(u)))
108 { return run_StateT % std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))) % snd(std::forward<U>(u)); }
109 };
110
111 struct closure {
112 template <is_StateT ST, class Fn, class T>
113 constexpr auto operator()(ST&& x, Fn&& f, T&& t) const noexcept(
114 noexcept(
115 mpc::bind(
116 run_StateT % std::forward<ST>(x) % std::forward<T>(t),
117 partial(nested_closure{}, std::forward<Fn>(f)))))
118 -> decltype(
119 mpc::bind(
120 run_StateT % std::forward<ST>(x) % std::forward<T>(t),
121 partial(nested_closure{}, std::forward<Fn>(f)))) {
122 return
123 mpc::bind(
124 run_StateT % std::forward<ST>(x) % std::forward<T>(t),
125 partial(nested_closure{}, std::forward<Fn>(f)));
126 }
127 };
128
129 template <is_StateT ST, class Fn>
130 constexpr auto operator()(ST&& x, Fn&& f) const noexcept(
131 noexcept( make_StateT<S>(partial(closure{}, std::forward<ST>(x), std::forward<Fn>(f)))))
132 -> decltype(make_StateT<S>(partial(closure{}, std::forward<ST>(x), std::forward<Fn>(f)))) {
133 return make_StateT<S>(partial(closure{}, std::forward<ST>(x), std::forward<Fn>(f)));
134 }
135 };
136
137 static constexpr bind_op bind{};
138 };
139
143 template <class S, monad M>
144 struct functor_traits<StateT<S, M>> {
145 // fmap :: (a -> b) -> f a -> f b
146 struct fmap_op {
147 struct nested_closure {
148 template <class Fn, class U>
149 constexpr auto operator()(Fn&& f, U&& u) const
150 noexcept(noexcept(std::make_pair(std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))), snd(std::forward<U>(u)))))
151 -> decltype( std::make_pair(std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))), snd(std::forward<U>(u))))
152 { return std::make_pair(std::invoke(std::forward<Fn>(f), fst(std::forward<U>(u))), snd(std::forward<U>(u))); }
153 };
154
155 struct closure {
156 template <class Fn, is_StateT ST, class T>
157 constexpr auto operator()(Fn&& f, ST&& x, T&& t) const noexcept(
158 noexcept(
159 mpc::fmap(
160 partial(nested_closure{}, std::forward<Fn>(f)),
161 run_StateT % std::forward<ST>(x) % std::forward<T>(t))))
162 -> decltype(
163 mpc::fmap(
164 partial(nested_closure{}, std::forward<Fn>(f)),
165 run_StateT % std::forward<ST>(x) % std::forward<T>(t))) {
166 return
167 mpc::fmap(
168 partial(nested_closure{}, std::forward<Fn>(f)),
169 run_StateT % std::forward<ST>(x) % std::forward<T>(t));
170 }
171 };
172
173 template <class Fn, is_StateT ST>
174 constexpr auto operator()(Fn&& f, ST&& x) const noexcept(
175 noexcept( make_StateT<S>(partial(closure{}, std::forward<Fn>(f), std::forward<ST>(x)))))
176 -> decltype(make_StateT<S>(partial(closure{}, std::forward<Fn>(f), std::forward<ST>(x)))) {
177 return make_StateT<S>(partial(closure{}, std::forward<Fn>(f), std::forward<ST>(x)));
178 }
179 };
180
181 static constexpr fmap_op fmap{};
182 static constexpr auto replace2nd = functors::replace2nd;
183 };
184
192 template <class S, monad M>
195 struct pure_op {
196 struct closure {
197 template <class A, class T>
198 constexpr auto operator()(A&& a, T&& t) const noexcept(
199 noexcept( returns<M>(std::make_pair(std::forward<A>(a), std::forward<T>(t)))))
200 -> decltype(returns<M>(std::make_pair(std::forward<A>(a), std::forward<T>(t)))) {
201 return returns<M>(std::make_pair(std::forward<A>(a), std::forward<T>(t)));
202 }
203 };
204
205 template <class A>
206 constexpr auto operator()(A&& a) const noexcept(
207 noexcept( make_StateT<S>(partial(closure{}, std::forward<A>(a)))))
208 -> decltype(make_StateT<S>(partial(closure{}, std::forward<A>(a)))) {
209 return make_StateT<S>(partial(closure{}, std::forward<A>(a)));
210 }
211 };
212
213 static constexpr pure_op pure{};
214 static constexpr auto seq_apply = monads::seq_apply;
215 static constexpr auto liftA2 = applicatives::liftA2;
216 static constexpr auto discard2nd = applicatives::discard2nd;
217 static constexpr auto discard1st = monads::discard1st;
218 };
219
223 namespace detail {
224 template <class ST>
226
227 template <is_StateT ST>
230 struct empty_op {
231 struct closure {
232 template <class T>
233 constexpr auto operator()() const noexcept(
234 noexcept( *mpc::empty<StateT_monad_t<ST>>))
235 -> decltype(*mpc::empty<StateT_monad_t<ST>>) {
236 return *mpc::empty<StateT_monad_t<ST>>;
237 }
238 };
239
240 constexpr auto operator()() const noexcept(
241 noexcept( make_StateT<StateT_state_t<ST>>(closure{})))
242 -> decltype(make_StateT<StateT_state_t<ST>>(closure{})) {
243 return make_StateT<StateT_state_t<ST>>(closure{});
244 }
245 };
246
247 static constexpr empty_op empty{};
248 };
249
250 template <class ST>
252
253 template <is_StateT ST>
256 struct combine_op {
257 struct closure {
258 template <is_StateT ST1, is_StateT ST2, class T>
259 constexpr auto operator()(ST1&& x, ST2&& y, T&& t) const
260 noexcept(noexcept(mpc::combine(run_StateT % std::forward<ST1>(x) % t, run_StateT % std::forward<ST2>(y) % t)))
261 -> decltype( mpc::combine(run_StateT % std::forward<ST1>(x) % t, run_StateT % std::forward<ST2>(y) % t)) {
262 auto t2 = t;
263 return mpc::combine(run_StateT % std::forward<ST1>(x) % std::forward<T>(t), run_StateT % std::forward<ST2>(y) % std::move(t2));
264 }
265 };
266
267 template <is_StateT ST1, is_StateT ST2>
268 constexpr auto operator()(ST1&& x, ST2&& y) const
269 noexcept(noexcept(make_StateT<StateT_state_t<ST>>(partial(closure{}, std::forward<ST1>(x), std::forward<ST2>(y)))))
270 -> decltype( make_StateT<StateT_state_t<ST>>(partial(closure{}, std::forward<ST1>(x), std::forward<ST2>(y)))) {
271 return make_StateT<StateT_state_t<ST>>(partial(closure{}, std::forward<ST1>(x), std::forward<ST2>(y)));
272 }
273 };
274
275 static constexpr combine_op combine{};
276 };
277 } // namespace detail
278
279 template <class S, monad M>
283
288 template <class S, monad M>
291 struct lift_op {
292 struct nested_closure {
293 template <class T, class A>
294 constexpr auto operator()(T&& t, A&& a) const
295 noexcept(noexcept(std::make_pair(std::forward<A>(a), std::forward<T>(t))))
296 -> decltype( std::make_pair(std::forward<A>(a), std::forward<T>(t))) {
297 return std::make_pair(std::forward<A>(a), std::forward<T>(t));
298 }
299 };
300
301 struct closure {
302 template <monad N, class T>
303 constexpr auto operator()(N&& n, T&& t) const
304 noexcept(noexcept(mpc::fmap(partial(nested_closure{}, std::forward<T>(t)), std::forward<N>(n))))
305 -> decltype( mpc::fmap(partial(nested_closure{}, std::forward<T>(t)), std::forward<N>(n))) {
306 return mpc::fmap(partial(nested_closure{}, std::forward<T>(t)), std::forward<N>(n));
307 }
308 };
309
310 template <monad N>
311 constexpr auto operator()(N&& n) const
312 noexcept(noexcept(make_StateT<S>(partial(closure{}, std::forward<N>(n)))))
313 -> decltype( make_StateT<S>(partial(closure{}, std::forward<N>(n)))) {
314 return make_StateT<S>(partial(closure{}, std::forward<N>(n)));
315 }
316 };
317
318 static constexpr lift_op lift{};
319 };
320
323 template <class S, monad M>
325 struct state_op {
326 template <copy_constructible_object Fn>
327 constexpr auto operator()(Fn&& f) const noexcept(
328 noexcept( make_StateT<S>(compose(mpc::returns<M>, std::forward<Fn>(f)))))
329 -> decltype(make_StateT<S>(compose(mpc::returns<M>, std::forward<Fn>(f)))) {
330 return make_StateT<S>(compose(mpc::returns<M>, std::forward<Fn>(f)));
331 }
332 };
333
334 static constexpr state_op state{};
335 static constexpr auto gets = states::gets<StateT<S, M>>;
336 static constexpr auto put = states::put<StateT<S, M>>;
337 };
338
339 // Grobal methods:
340 // [x] eval_StateT
341 // [x] exec_StateT
342 // [x] map_StateT
343 // [x] with_StateT
344
345 // eval_StateT, exec_StateT, map_StateT, with_StateT
346 namespace detail {
348 template <is_StateT ST, class T>
349 constexpr auto operator()(ST&& x, T&& t) const noexcept(
350 noexcept( mpc::fmap(fst, run_StateT % std::forward<ST>(x) % std::forward<T>(t))))
351 -> decltype(mpc::fmap(fst, run_StateT % std::forward<ST>(x) % std::forward<T>(t))) {
352 return mpc::fmap(fst, run_StateT % std::forward<ST>(x) % std::forward<T>(t));
353 }
354 };
355
357 template <is_StateT ST, class T>
358 constexpr auto operator()(ST&& x, T&& t) const noexcept(
359 noexcept( mpc::fmap(snd, run_StateT % std::forward<ST>(x) % std::forward<T>(t))))
360 -> decltype(mpc::fmap(snd, run_StateT % std::forward<ST>(x) % std::forward<T>(t))) {
361 return mpc::fmap(snd, run_StateT % std::forward<ST>(x) % std::forward<T>(t));
362 }
363 };
364
366 template <class Fn, is_StateT ST>
367 constexpr auto operator()(Fn&& f, ST&& x) const noexcept(
368 noexcept( make_StateT<StateT_state_t<ST>>(compose(std::forward<Fn>(f), run_StateT % std::forward<ST>(x)))))
369 -> decltype(make_StateT<StateT_state_t<ST>>(compose(std::forward<Fn>(f), run_StateT % std::forward<ST>(x)))) {
370 return make_StateT<StateT_state_t<ST>>(compose(std::forward<Fn>(f), run_StateT % std::forward<ST>(x)));
371 }
372 };
373
375 template <class Fn, is_StateT ST>
376 constexpr auto operator()(Fn&& f, ST&& x) const noexcept(
377 noexcept( make_StateT<StateT_state_t<ST>>(compose(run_StateT % std::forward<ST>(x), std::forward<Fn>(f)))))
378 -> decltype(make_StateT<StateT_state_t<ST>>(compose(run_StateT % std::forward<ST>(x), std::forward<Fn>(f)))) {
379 return make_StateT<StateT_state_t<ST>>(compose(run_StateT % std::forward<ST>(x), std::forward<Fn>(f)));
380 }
381 };
382 } // namespace detail
383
384 inline namespace cpo {
385 inline constexpr partial<detail::eval_StateT_op> eval_StateT{};
386
387 inline constexpr partial<detail::exec_StateT_op> exec_StateT{};
388
389 inline constexpr partial<detail::map_StateT_op> map_StateT{};
390
391 inline constexpr partial<detail::with_StateT_op> with_StateT{};
392 } // namespace cpo
393} // namespace mpc
394
395// clang-format on
has_alternative_traits_combine
Definition: alternative.hpp:25
has_alternative_traits_empty
Definition: alternative.hpp:19
Requires applicative and bind is valid in monad_traits .
Definition: monad.hpp:25
constexpr partial< detail::liftA2_op > liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Definition: applicative.hpp:173
constexpr auto discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:182
constexpr partial< detail::fmap_op > fmap
fmap :: (a -> b) -> f a -> f b
Definition: applicative.hpp:161
constexpr partial< detail::liftA2_op > liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Definition: applicative.hpp:102
constexpr partial< detail::_fst::get_op< 1 > > snd
Returns the second element of the given tuple-like object.
Definition: fst.hpp:34
constexpr partial< detail::bind_op > bind
bind :: forall a b. m a -> (a -> m b) -> m b
Definition: monad.hpp:45
constexpr partial< detail::compose_op > compose
Function composition.
Definition: compose.hpp:35
constexpr partial< detail::discard1st_op > discard1st
discard1st :: f a -> f b -> f b
Definition: applicative.hpp:108
constexpr partial< detail::replace2nd_op > replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:53
constexpr partial< detail::lift_op< TR > > lift
lift :: (Monad m) => m a -> t m a
Definition: class.hpp:35
constexpr detail::empty_op< F > empty
empty :: f a
Definition: alternative.hpp:71
constexpr partial< detail::combine_op > combine
combine :: f a -> f a -> f a
Definition: alternative.hpp:74
constexpr partial< detail::discard2nd_op > discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:105
constexpr partial< detail::seq_apply_op > seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: applicative.hpp:99
constexpr partial< detail::put_op< ST > > put
put :: s -> m ()
Definition: class.hpp:69
constexpr partial< detail::pure_op< F > > pure
pure :: a -> f a
Definition: applicative.hpp:96
constexpr detail::gets_op< ST > gets
gets :: m s
Definition: class.hpp:65
constexpr partial< detail::_fst::get_op< 0 > > fst
Returns the first element of the given tuple-like object.
Definition: fst.hpp:29
constexpr partial< detail::state_op< ST > > state
state :: (s -> (a, s)) -> m a
Definition: class.hpp:61
constexpr auto replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:65
constexpr partial< detail::discard1st_op > discard1st
discard1st :: f a -> f b -> f b
Definition: monad.hpp:109
constexpr partial< detail::seq_apply_op > seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: monad.hpp:106
newtype Identity a = Identity { runIdentity :: a }
Definition: identity.hpp:15
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
Definition: stateT.hpp:29
class Applicative f => Alternative f where
Definition: alternative.hpp:14
class Functor f => Applicative f where
Definition: applicative.hpp:18
combine :: f a -> f a -> f a
Definition: alternative.hpp:58
empty :: f a
Definition: alternative.hpp:47
Definition: stateT.hpp:347
Definition: stateT.hpp:356
Definition: stateT.hpp:38
Definition: stateT.hpp:62
Definition: stateT.hpp:365
Definition: stateT.hpp:73
Definition: stateT.hpp:374
Definition: function.hpp:29
class Functor f where
Definition: functor.hpp:14
Definition: holding.hpp:7
Definition: class.hpp:13
class Applicative m => Monad m where
Definition: monad.hpp:15
class (forall m. Monad m => Monad (t m)) => MonadTrans t where
Definition: class.hpp:11
Implements a perfect-forwarding call wrapper.
Definition: partial.hpp:63