mpc
Haskell-like feature supports in C++
either.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <functional> // std::invoke
4#include <variant>
7#include <mpc/prelude.hpp>
10
11// clang-format off
12
13namespace mpc {
14 // either
15 // https://hackage.haskell.org/package/base-4.15.0.0/docs/src/Data-Either.html#Either
16
17 template <class T>
18 using left_t = single<T, std::false_type>;
19
20 template <class T>
21 using right_t = single<T, std::true_type>;
22
23 template <class T>
24 constexpr left_t<std::unwrap_ref_decay_t<T>> make_left(T&& t) {
25 return std::forward<T>(t);
26 }
27
28 template <class T>
29 constexpr right_t<std::unwrap_ref_decay_t<T>> make_right(T&& t) {
30 return std::forward<T>(t);
31 }
32
34 template <class T, class U>
35 using either = std::variant<left_t<T>, right_t<U>>;
36
37 namespace detail {
38 template <class>
39 struct is_either_impl : std::false_type {};
40
41 template <class T, class U>
42 struct is_either_impl<either<T, U>> : std::true_type {};
43 } // namespace detail
44
45 template <class T>
46 concept is_either = detail::is_either_impl<std::remove_cvref_t<T>>::value;
47
48 template <class T, class U>
49 struct holding<either<T, U>> : std::type_identity<U> {};
50
54 template <class T1, class T2>
55 struct functor_traits<either<T1, T2>> {
57 struct fmap_op {
58 template <class F, is_either E>
59 constexpr auto operator()(F&& f, E&& e) const
61 std::unwrap_ref_decay_t<std::invoke_result_t<F, alternative_value_t<1, E>>>> {
62 if (e.index() == 0) {
63 return std::get<0>(std::forward<E>(e));
64 } else {
65 return make_right(std::invoke(std::forward<F>(f), *std::get<1>(std::forward<E>(e))));
66 }
67 }
68 };
69
70 static constexpr fmap_op fmap{};
71 static constexpr auto replace2nd = functors::replace2nd;
72 };
73
77 template <class T1, class T2>
78 struct monad_traits<either<T1, T2>> {
80 struct bind_op {
81 template <is_either E, class F>
82 constexpr auto operator()(E&& e, F&& f) const //
83 -> decltype(std::invoke(std::forward<F>(f), *std::get<1>(std::forward<E>(e)))) {
84 if (e.index() == 0) {
85 return std::get<0>(std::forward<E>(e));
86 } else {
87 return std::invoke(std::forward<F>(f), *std::get<1>(std::forward<E>(e)));
88 }
89 }
90 };
91
92 static constexpr bind_op bind{};
93 };
94
99 template <class T1, class T2>
100 struct applicative_traits<either<T1, T2>> {
102 struct pure_op {
103 template <class U>
104 constexpr auto operator()(U&& u) const //
106 return make_right(std::forward<U>(u));
107 }
108 };
109
111 struct seq_apply_op {
112 template <is_either E1, is_either E2>
113 constexpr auto operator()(E1&& e1, E2&& e2) const
114 -> either<
115 std::common_type_t<
117 alternative_value_t<0, decltype(mpc::fmap(*std::get<1>(std::forward<E1>(e1)), std::forward<E2>(e2)))>
118 >,
119 alternative_value_t<1, decltype(mpc::fmap(*std::get<1>(std::forward<E1>(e1)), std::forward<E2>(e2)))>
120 > {
121 if (e1.index() == 0) {
122 return std::get<0>(std::forward<E1>(e1));
123 } else {
124 return mpc::fmap(*std::get<1>(std::forward<E1>(e1)), std::forward<E2>(e2));
125 }
126 }
127 };
128
129 static constexpr pure_op pure{};
130 static constexpr seq_apply_op seq_apply{};
131 static constexpr auto liftA2 = applicatives::liftA2;
132 static constexpr auto discard2nd = applicatives::discard2nd;
133 static constexpr auto discard1st = monads::discard1st;
134 };
135} // namespace mpc
136
137// clang-format on
typename std::variant_alternative_t< Idx, std::remove_cvref_t< Variant > >::value_type alternative_value_t
alternative_value_t
Definition: alternative_value_t.hpp:13
std::variant< left_t< T >, right_t< U > > either
data Either a b = Left a | Right b
Definition: either.hpp:35
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::bind_op > bind
bind :: forall a b. m a -> (a -> m b) -> m b
Definition: monad.hpp:45
constexpr partial< detail::replace2nd_op > replace2nd
replace2nd :: a -> f b -> f a
Definition: functor.hpp:53
constexpr partial< detail::seq_apply_op > seq_apply
seq_apply :: f (a -> b) -> f a -> f b
Definition: applicative.hpp:99
constexpr partial< detail::pure_op< F > > pure
pure :: a -> f a
Definition: applicative.hpp:96
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
class Functor f => Applicative f where
Definition: applicative.hpp:18
Definition: either.hpp:39
class Functor f where
Definition: functor.hpp:14
Definition: holding.hpp:7
class Applicative m => Monad m where
Definition: monad.hpp:15
A class that holds a single value.
Definition: single.hpp:15