rsl 1.1.0
ROS Support Library
Loading...
Searching...
No Matches
monad.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <tl_expected/expected.hpp>
4
5#include <optional>
6
7namespace rsl {
8
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};
29}
30
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());
48}
49
60template <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
78template <typename Fn, typename G>
79[[nodiscard]] constexpr auto mcompose(Fn fn, G g) {
80 return [=](auto value) { return mbind(fn(value), g); };
81}
82
96template <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
109template <typename T, typename E>
110[[nodiscard]] constexpr auto has_error(tl::expected<T, E> const& exp) {
111 return !exp.has_value();
112}
113
121template <typename T, typename E>
122[[nodiscard]] constexpr auto has_value(tl::expected<T, E> const& exp) {
123 return exp.has_value();
124}
125
136template <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
148template <typename>
149constexpr inline bool is_optional_impl = false;
150template <typename T>
151constexpr inline bool is_optional_impl<std::optional<T>> = true;
152template <typename T>
153constexpr inline bool is_optional = is_optional_impl<std::remove_cv_t<std::remove_reference_t<T>>>;
154
155} // namespace rsl
156
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));
173}
174
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);
190}
191
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));
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