3#include <tl_expected/expected.hpp>
22template <
typename T,
typename Fn>
23[[nodiscard]]
constexpr auto mbind(std::optional<T>
const& opt, Fn fn)
24 -> std::invoke_result_t<Fn, T> {
25 static_assert(std::is_convertible_v<std::nullopt_t, std::invoke_result_t<Fn, T>>,
26 "Fn must return a std::optional");
27 if (opt)
return fn(opt.value());
28 return std::invoke_result_t<Fn, T>{std::nullopt};
43template <
typename T,
typename E,
typename Fn>
44[[nodiscard]]
constexpr auto mbind(tl::expected<T, E>
const& exp, Fn fn)
45 -> std::invoke_result_t<Fn, T> {
46 if (exp)
return fn(exp.value());
47 return tl::unexpected(exp.error());
61[[nodiscard]]
auto mtry(Fn fn) -> tl::expected<std::invoke_result_t<Fn>, std::exception_ptr>
try {
64 return tl::unexpected(std::current_exception());
78template <
typename Fn,
typename G>
79[[nodiscard]]
constexpr auto mcompose(Fn fn, G g) {
80 return [=](
auto value) {
return mbind(fn(value), g); };
96template <
typename T,
typename G,
typename... Ts>
97[[nodiscard]]
constexpr auto mcompose(T t, G g, Ts... vars) {
109template <
typename T,
typename E>
110[[nodiscard]]
constexpr auto has_error(tl::expected<T, E>
const& exp) {
111 return !exp.has_value();
121template <
typename T,
typename E>
122[[nodiscard]]
constexpr auto has_value(tl::expected<T, E>
const& exp) {
123 return exp.has_value();
136template <
typename E,
typename... Args>
137[[nodiscard]]
constexpr auto maybe_error(tl::expected<Args, E>... args) {
138 auto maybe = std::optional<E>();
141 if (maybe.has_value())
return;
149constexpr inline bool is_optional_impl =
false;
151constexpr inline bool is_optional_impl<std::optional<T>> =
true;
153constexpr inline bool is_optional = is_optional_impl<std::remove_cv_t<std::remove_reference_t<T>>>;
168template <
typename T,
typename Fn,
typename = std::enable_if_t<rsl::is_optional<T>>,
169 typename = std::enable_if_t<std::is_invocable_v<
170 Fn,
typename std::remove_cv_t<std::remove_reference_t<T>>::value_type>>>
171[[nodiscard]]
constexpr auto operator|(T&& opt, Fn&& fn) {
172 return rsl::mbind(std::forward<T>(opt), std::forward<Fn>(fn));
187template <
typename T,
typename E,
typename Fn>
188[[nodiscard]]
constexpr auto operator|(tl::expected<T, E>
const& exp, Fn fn) {
189 return rsl::mbind(exp, fn);
203template <
typename T,
typename Fn,
typename = std::enable_if_t<!rsl::is_optional<T>>>
204[[nodiscard]]
constexpr auto operator|(T&& val, Fn&& fn) ->
205 typename std::enable_if_t<std::is_invocable_v<Fn, T>, std::invoke_result_t<Fn, T>> {
206 return std::invoke(std::forward<Fn>(fn), std::forward<T>(val));
constexpr auto operator|(T &&opt, Fn &&fn)
Overload of the | operator as bind.
Definition monad.hpp:171
constexpr auto mbind(std::optional< T > const &opt, Fn fn) -> std::invoke_result_t< Fn, T >
Monad optional bind.
Definition monad.hpp:23
constexpr auto has_error(tl::expected< T, E > const &exp)
Test if expected type is Error.
Definition monad.hpp:110
constexpr auto maybe_error(tl::expected< Args, E >... args)
Tests if any of the expected args passed in has an error.
Definition monad.hpp:137
constexpr auto mcompose(Fn fn, G g)
Monadic compose two monad functions.
Definition monad.hpp:79
constexpr auto has_value(tl::expected< T, E > const &exp)
Test if expected type is Value.
Definition monad.hpp:122
auto mtry(Fn fn) -> tl::expected< std::invoke_result_t< Fn >, std::exception_ptr > try
Monadic try, used to lift a function that throws an exception into one that returns an tl::expected<T...
Definition monad.hpp:61