1/*!
2@file
3Defines `boost::hana::monadic_fold_right`.
4
5Copyright Louis Dionne 2013-2022
6Distributed under the Boost Software License, Version 1.0.
7(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8 */
9
10#ifndef BOOST_HANA_MONADIC_FOLD_RIGHT_HPP
11#define BOOST_HANA_MONADIC_FOLD_RIGHT_HPP
12
13#include <boost/hana/fwd/monadic_fold_right.hpp>
14
15#include <boost/hana/chain.hpp>
16#include <boost/hana/concept/foldable.hpp>
17#include <boost/hana/concept/monad.hpp>
18#include <boost/hana/config.hpp>
19#include <boost/hana/core/dispatch.hpp>
20#include <boost/hana/detail/decay.hpp>
21#include <boost/hana/fold_left.hpp>
22#include <boost/hana/functional/curry.hpp>
23#include <boost/hana/functional/partial.hpp>
24#include <boost/hana/lift.hpp>
25
26#include <type_traits>
27
28
29namespace boost { namespace hana {
30 //! @cond
31 template <typename M>
32 template <typename Xs, typename State, typename F>
33 constexpr decltype(auto) monadic_fold_right_t<M>::operator()(Xs&& xs, State&& state, F&& f) const {
34 using S = typename hana::tag_of<Xs>::type;
35 using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl<S>,
36 hana::Foldable<S>::value
37 );
38
39 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
40 static_assert(hana::Monad<M>::value,
41 "hana::monadic_fold_right<M> requires 'M' to be a Monad");
42
43 static_assert(hana::Foldable<S>::value,
44 "hana::monadic_fold_right<M>(xs, state, f) requires 'xs' to be Foldable");
45 #endif
46
47 return MonadicFoldRight::template apply<M>(static_cast<Xs&&>(xs),
48 static_cast<State&&>(state),
49 static_cast<F&&>(f));
50 }
51 //! @endcond
52
53 //! @cond
54 template <typename M>
55 template <typename Xs, typename F>
56 constexpr decltype(auto) monadic_fold_right_t<M>::operator()(Xs&& xs, F&& f) const {
57 using S = typename hana::tag_of<Xs>::type;
58 using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl<S>,
59 hana::Foldable<S>::value
60 );
61
62 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
63 static_assert(hana::Monad<M>::value,
64 "hana::monadic_fold_right<M> requires 'M' to be a Monad");
65
66 static_assert(hana::Foldable<S>::value,
67 "hana::monadic_fold_right<M>(xs, f) requires 'xs' to be Foldable");
68 #endif
69 return MonadicFoldRight::template apply<M>(static_cast<Xs&&>(xs),
70 static_cast<F&&>(f));
71 }
72 //! @endcond
73
74 namespace detail {
75 struct foldrM_helper {
76 template <typename F, typename K, typename X, typename Z>
77 constexpr decltype(auto) operator()(F&& f, K&& k, X&& x, Z&& z) const {
78 return hana::chain(
79 static_cast<F&&>(f)(
80 static_cast<X&&>(x),
81 static_cast<Z&&>(z)
82 ),
83 static_cast<K&&>(k)
84 );
85 }
86 };
87
88 template <typename End, typename M, typename F>
89 struct monadic_foldr1_helper {
90 F f;
91 template <typename X, typename Y>
92 constexpr decltype(auto) operator()(X&& x, Y&& y) const
93 { return f(static_cast<X&&>(x), static_cast<Y&&>(y)); }
94 template <typename X>
95 constexpr decltype(auto) operator()(X&& x, End) const
96 { return hana::lift<M>(static_cast<X&&>(x)); }
97 };
98 }
99
100 template <typename T, bool condition>
101 struct monadic_fold_right_impl<T, when<condition>> : default_ {
102 // with state
103 template <typename M, typename Xs, typename S, typename F>
104 static constexpr decltype(auto) apply(Xs&& xs, S&& s, F&& f) {
105 return hana::fold_left(
106 static_cast<Xs&&>(xs),
107 hana::lift<M>,
108 hana::curry<3>(hana::partial(
109 detail::foldrM_helper{}, static_cast<F&&>(f)
110 ))
111 )(static_cast<S&&>(s));
112 }
113
114 // without state
115 template <typename M, typename Xs, typename F>
116 static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
117 struct end { };
118 using G = detail::monadic_foldr1_helper<end, M, typename detail::decay<F>::type>;
119 decltype(auto) result = hana::monadic_fold_right<M>(
120 static_cast<Xs&&>(xs),
121 end{},
122 G{static_cast<F&&>(f)}
123 );
124
125 static_assert(!std::is_same<
126 std::remove_reference_t<decltype(result)>,
127 decltype(hana::lift<M>(end{}))
128 >{},
129 "hana::monadic_fold_right<M>(xs, f) requires 'xs' to be non-empty");
130 return result;
131 }
132 };
133}} // end namespace boost::hana
134
135#endif // !BOOST_HANA_MONADIC_FOLD_RIGHT_HPP
136

source code of boost/libs/hana/include/boost/hana/monadic_fold_right.hpp