rsl  1.1.0
ROS Support Library
monad.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <tl_expected/expected.hpp>
4 
5 #include <optional>
6 
7 namespace rsl {
8 
22 template <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};
29 }
30 
43 template <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());
48 }
49 
60 template <typename Fn>
61 [[nodiscard]] auto mtry(Fn fn) -> tl::expected<std::invoke_result_t<Fn>, std::exception_ptr> try {
62  return fn();
63 } catch (...) {
64  return tl::unexpected(std::current_exception());
65 }
66 
78 template <typename Fn, typename G>
79 [[nodiscard]] constexpr auto mcompose(Fn fn, G g) {
80  return [=](auto value) { return mbind(fn(value), g); };
81 }
82 
96 template <typename T, typename G, typename... Ts>
97 [[nodiscard]] constexpr auto mcompose(T t, G g, Ts... vars) {
98  auto exp = mcompose(t, g);
99  return mcompose(exp, vars...);
100 }
101 
109 template <typename T, typename E>
110 [[nodiscard]] constexpr auto has_error(tl::expected<T, E> const& exp) {
111  return !exp.has_value();
112 }
113 
121 template <typename T, typename E>
122 [[nodiscard]] constexpr auto has_value(tl::expected<T, E> const& exp) {
123  return exp.has_value();
124 }
125 
136 template <typename E, typename... Args>
137 [[nodiscard]] constexpr auto maybe_error(tl::expected<Args, E>... args) {
138  auto maybe = std::optional<E>();
139  (
140  [&](auto& exp) {
141  if (maybe.has_value()) return;
142  if (has_error(exp)) maybe = exp.error();
143  }(args),
144  ...);
145  return maybe;
146 }
147 
148 template <typename>
149 constexpr inline bool is_optional_impl = false;
150 template <typename T>
151 constexpr inline bool is_optional_impl<std::optional<T>> = true;
152 template <typename T>
153 constexpr inline bool is_optional = is_optional_impl<std::remove_cv_t<std::remove_reference_t<T>>>;
154 
155 } // namespace rsl
156 
168 template <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(opt, fn);
173 }
174 
187 template <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);
190 }
191 
203 template <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));
207 }
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