File indexing completed on 2025-01-18 09:38:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_HANA_MONADIC_FOLD_RIGHT_HPP
0011 #define BOOST_HANA_MONADIC_FOLD_RIGHT_HPP
0012
0013 #include <boost/hana/fwd/monadic_fold_right.hpp>
0014
0015 #include <boost/hana/chain.hpp>
0016 #include <boost/hana/concept/foldable.hpp>
0017 #include <boost/hana/concept/monad.hpp>
0018 #include <boost/hana/config.hpp>
0019 #include <boost/hana/core/dispatch.hpp>
0020 #include <boost/hana/detail/decay.hpp>
0021 #include <boost/hana/fold_left.hpp>
0022 #include <boost/hana/functional/curry.hpp>
0023 #include <boost/hana/functional/partial.hpp>
0024 #include <boost/hana/lift.hpp>
0025
0026 #include <type_traits>
0027
0028
0029 namespace boost { namespace hana {
0030
0031 template <typename M>
0032 template <typename Xs, typename State, typename F>
0033 constexpr decltype(auto) monadic_fold_right_t<M>::operator()(Xs&& xs, State&& state, F&& f) const {
0034 using S = typename hana::tag_of<Xs>::type;
0035 using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl<S>,
0036 hana::Foldable<S>::value
0037 );
0038
0039 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
0040 static_assert(hana::Monad<M>::value,
0041 "hana::monadic_fold_right<M> requires 'M' to be a Monad");
0042
0043 static_assert(hana::Foldable<S>::value,
0044 "hana::monadic_fold_right<M>(xs, state, f) requires 'xs' to be Foldable");
0045 #endif
0046
0047 return MonadicFoldRight::template apply<M>(static_cast<Xs&&>(xs),
0048 static_cast<State&&>(state),
0049 static_cast<F&&>(f));
0050 }
0051
0052
0053
0054 template <typename M>
0055 template <typename Xs, typename F>
0056 constexpr decltype(auto) monadic_fold_right_t<M>::operator()(Xs&& xs, F&& f) const {
0057 using S = typename hana::tag_of<Xs>::type;
0058 using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl<S>,
0059 hana::Foldable<S>::value
0060 );
0061
0062 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
0063 static_assert(hana::Monad<M>::value,
0064 "hana::monadic_fold_right<M> requires 'M' to be a Monad");
0065
0066 static_assert(hana::Foldable<S>::value,
0067 "hana::monadic_fold_right<M>(xs, f) requires 'xs' to be Foldable");
0068 #endif
0069 return MonadicFoldRight::template apply<M>(static_cast<Xs&&>(xs),
0070 static_cast<F&&>(f));
0071 }
0072
0073
0074 namespace detail {
0075 struct foldrM_helper {
0076 template <typename F, typename K, typename X, typename Z>
0077 constexpr decltype(auto) operator()(F&& f, K&& k, X&& x, Z&& z) const {
0078 return hana::chain(
0079 static_cast<F&&>(f)(
0080 static_cast<X&&>(x),
0081 static_cast<Z&&>(z)
0082 ),
0083 static_cast<K&&>(k)
0084 );
0085 }
0086 };
0087
0088 template <typename End, typename M, typename F>
0089 struct monadic_foldr1_helper {
0090 F f;
0091 template <typename X, typename Y>
0092 constexpr decltype(auto) operator()(X&& x, Y&& y) const
0093 { return f(static_cast<X&&>(x), static_cast<Y&&>(y)); }
0094 template <typename X>
0095 constexpr decltype(auto) operator()(X&& x, End) const
0096 { return hana::lift<M>(static_cast<X&&>(x)); }
0097 };
0098 }
0099
0100 template <typename T, bool condition>
0101 struct monadic_fold_right_impl<T, when<condition>> : default_ {
0102
0103 template <typename M, typename Xs, typename S, typename F>
0104 static constexpr decltype(auto) apply(Xs&& xs, S&& s, F&& f) {
0105 return hana::fold_left(
0106 static_cast<Xs&&>(xs),
0107 hana::lift<M>,
0108 hana::curry<3>(hana::partial(
0109 detail::foldrM_helper{}, static_cast<F&&>(f)
0110 ))
0111 )(static_cast<S&&>(s));
0112 }
0113
0114
0115 template <typename M, typename Xs, typename F>
0116 static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
0117 struct end { };
0118 using G = detail::monadic_foldr1_helper<end, M, typename detail::decay<F>::type>;
0119 decltype(auto) result = hana::monadic_fold_right<M>(
0120 static_cast<Xs&&>(xs),
0121 end{},
0122 G{static_cast<F&&>(f)}
0123 );
0124
0125 static_assert(!std::is_same<
0126 std::remove_reference_t<decltype(result)>,
0127 decltype(hana::lift<M>(end{}))
0128 >{},
0129 "hana::monadic_fold_right<M>(xs, f) requires 'xs' to be non-empty");
0130 return result;
0131 }
0132 };
0133 }}
0134
0135 #endif