mpc
Haskell-like feature supports in C++
maybe.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 // maybe
15 // https://hackage.haskell.org/package/base-4.15.0.0/docs/src/GHC-Maybe.html#Maybe
16
17 struct nothing_t {
18 inline constexpr auto operator<=>(const nothing_t&) const = default;
19 }; // struct nothing_t
20
21 inline constexpr nothing_t nothing;
22
23 template <class T>
25
26 template <class T>
27 constexpr just_t<std::unwrap_ref_decay_t<T>> make_just(T&& t) {
28 return std::forward<T>(t);
29 }
30
32 template <class T>
33 using maybe = std::variant<nothing_t, just_t<T>>;
34
35 namespace detail {
36 template <class>
37 struct is_maybe_impl : std::false_type {};
38
39 template <class T>
40 struct is_maybe_impl<maybe<T>> : std::true_type {};
41 } // namespace detail
42
43 template <class T>
44 concept is_maybe = detail::is_maybe_impl<std::remove_cvref_t<T>>::value;
45
51 template <class T1>
52 struct functor_traits<maybe<T1>> {
54 struct fmap_op {
55 template <class F, is_maybe M>
56 constexpr auto operator()(F&& f, M&& x) const //
57 -> maybe<std::unwrap_ref_decay_t<decltype(
58 std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M>(x))))>> {
59 if (x.index() == 0) {
60 return nothing;
61 } else {
62 return make_just(std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M>(x))));
63 }
64 }
65 };
66
68 struct replace2nd_op {
69 template <class U, is_maybe M>
70 constexpr auto operator()(U&& u, M&& m) const //
72 if (m.index() == 0) {
73 return nothing;
74 } else {
75 return make_just(std::forward<U>(u));
76 }
77 }
78 };
79
80 static constexpr fmap_op fmap{};
81 static constexpr replace2nd_op replace2nd{};
82 };
83
87 template <class T1>
88 struct monad_traits<maybe<T1>> {
90 struct bind_op {
91 template <is_maybe M, class F>
92 constexpr auto operator()(M&& x, F&& f) const //
93 -> decltype(std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M>(x)))) {
94 if (x.index() == 0) {
95 return nothing;
96 } else {
97 return std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M>(x)));
98 }
99 }
100 };
101
102 static constexpr bind_op bind{};
103 };
104
111 template <class T1>
114 struct pure_op {
115 template <class U>
116 constexpr auto operator()(U&& u) const //
118 return make_just(std::forward<U>(u));
119 }
120 };
121
123 struct seq_apply_op {
124 template <is_maybe M1, is_maybe M2>
125 constexpr auto operator()(M1&& f, M2&& x) const //
126 -> decltype(mpc::fmap(*std::get<1>(std::forward<M1>(f)), std::forward<M2>(x))) {
127 if (f.index() == 0) {
128 return nothing;
129 } else {
130 return mpc::fmap(*std::get<1>(std::forward<M1>(f)), std::forward<M2>(x));
131 }
132 }
133 };
134
136 struct liftA2_op {
137 template <class F, is_maybe M1, is_maybe M2>
138 constexpr auto operator()(F&& f, M1&& m1, M2&& m2) const //
139 -> maybe<std::unwrap_ref_decay_t<decltype(
140 std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M1>(m1)),
141 *std::get<1>(std::forward<M2>(m2))))>> {
142 if (m1.index() == 1 and m2.index() == 1) {
143 return make_just(std::invoke(std::forward<F>(f), *std::get<1>(std::forward<M1>(m1)),
144 *std::get<1>(std::forward<M2>(m2))));
145 } else {
146 return nothing;
147 }
148 }
149 };
150
151 static constexpr pure_op pure{};
152 static constexpr seq_apply_op seq_apply{};
153 static constexpr liftA2_op liftA2{};
154 static constexpr auto discard2nd = applicatives::discard2nd;
155 static constexpr auto discard1st = applicatives::discard1st_opt;
156 };
157
162 template <class T1>
164 struct empty_op {
165 constexpr auto operator()() const -> maybe<T1> {
166 return nothing;
167 }
168 };
169
170 struct combine_op {
171 template <is_maybe M1, is_maybe M2>
172 requires std::same_as<std::remove_cvref_t<M1>, std::remove_cvref_t<M2>>
173 constexpr auto operator()(M1&& m1, M2&& m2) const //
174 -> std::remove_cvref_t<M1> {
175 return (m1.index() == 1 ? m1 : m2);
176 }
177 };
178
179 static constexpr empty_op empty{};
180 static constexpr combine_op combine{};
181 };
182} // namespace mpc
183
184// clang-format on
std::variant< nothing_t, just_t< T > > maybe
data Maybe a = Nothing | Just a
Definition: maybe.hpp:33
constexpr auto discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:182
constexpr partial< detail::discard1st_opt_op > discard1st_opt
discard1st :: f a -> f b -> f b
Definition: applicative.hpp:194
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::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 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::pure_op< F > > pure
pure :: a -> f a
Definition: applicative.hpp:96
class Applicative f => Alternative f where
Definition: alternative.hpp:14
class Functor f => Applicative f where
Definition: applicative.hpp:18
Definition: maybe.hpp:37
class Functor f where
Definition: functor.hpp:14
class Applicative m => Monad m where
Definition: monad.hpp:15
Definition: maybe.hpp:17
A class that holds a single value.
Definition: single.hpp:15