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_LEFT_HPP
0011 #define BOOST_HANA_MONADIC_FOLD_LEFT_HPP
0012
0013 #include <boost/hana/fwd/monadic_fold_left.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_right.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_left_t<M>::operator()(Xs&& xs, State&& state, F&& f) const {
0034 using S = typename hana::tag_of<Xs>::type;
0035 using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_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_left<M> requires 'M' to be a Monad");
0042
0043 static_assert(hana::Foldable<S>::value,
0044 "hana::monadic_fold_left<M>(xs, state, f) requires 'xs' to be Foldable");
0045 #endif
0046
0047 return MonadicFoldLeft::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_left_t<M>::operator()(Xs&& xs, F&& f) const {
0057 using S = typename hana::tag_of<Xs>::type;
0058 using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_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_left<M> requires 'M' to be a Monad");
0065
0066 static_assert(hana::Foldable<S>::value,
0067 "hana::monadic_fold_left<M>(xs, f) requires 'xs' to be Foldable");
0068 #endif
0069
0070 return MonadicFoldLeft::template apply<M>(static_cast<Xs&&>(xs),
0071 static_cast<F&&>(f));
0072 }
0073
0074
0075 namespace detail {
0076 struct foldlM_helper {
0077 template <typename F, typename X, typename K, typename Z>
0078 constexpr decltype(auto) operator()(F&& f, X&& x, K&& k, Z&& z) const {
0079 return hana::chain(
0080 static_cast<F&&>(f)(
0081 static_cast<Z&&>(z),
0082 static_cast<X&&>(x)
0083 ),
0084 static_cast<K&&>(k)
0085 );
0086 }
0087 };
0088
0089 template <typename End, typename M, typename F>
0090 struct monadic_foldl1_helper {
0091 F f;
0092 template <typename X, typename Y>
0093 constexpr decltype(auto) operator()(X&& x, Y&& y) const
0094 { return f(static_cast<X&&>(x), static_cast<Y&&>(y)); }
0095 template <typename Y>
0096 constexpr decltype(auto) operator()(End, Y&& y) const
0097 { return hana::lift<M>(static_cast<Y&&>(y)); }
0098 };
0099 }
0100
0101 template <typename T, bool condition>
0102 struct monadic_fold_left_impl<T, when<condition>> : default_ {
0103
0104 template <typename M, typename Xs, typename S, typename F>
0105 static constexpr decltype(auto) apply(Xs&& xs, S&& s, F&& f) {
0106 return hana::fold_right(
0107 static_cast<Xs&&>(xs),
0108 hana::lift<M>,
0109 hana::curry<3>(hana::partial(
0110 detail::foldlM_helper{}, static_cast<F&&>(f)
0111 ))
0112 )(static_cast<S&&>(s));
0113 }
0114
0115
0116 template <typename M, typename Xs, typename F>
0117 static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
0118 struct end { };
0119 using G = detail::monadic_foldl1_helper<end, M, typename detail::decay<F>::type>;
0120 decltype(auto) result = hana::monadic_fold_left<M>(
0121 static_cast<Xs&&>(xs),
0122 end{},
0123 G{static_cast<F&&>(f)}
0124 );
0125
0126 static_assert(!std::is_same<
0127 std::remove_reference_t<decltype(result)>,
0128 decltype(hana::lift<M>(end{}))
0129 >{},
0130 "hana::monadic_fold_left<M>(xs, f) requires 'xs' to be non-empty");
0131 return result;
0132 }
0133 };
0134 }}
0135
0136 #endif