/*! @file Defines `boost::hana::monadic_fold_left`. @copyright Louis Dionne 2013-2016 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_MONADIC_FOLD_LEFT_HPP #define BOOST_HANA_MONADIC_FOLD_LEFT_HPP #include #include #include #include #include #include #include #include #include #include #include #include BOOST_HANA_NAMESPACE_BEGIN template struct monadic_fold_left_t { #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monad::value, "hana::monadic_fold_left requires 'M' to be a Monad"); #endif template constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const { using S = typename hana::tag_of::type; using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, hana::Foldable::value ); #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Foldable::value, "hana::monadic_fold_left(xs, state, f) requires 'xs' to be Foldable"); #endif return MonadicFoldLeft::template apply(static_cast(xs), static_cast(state), static_cast(f)); } template constexpr decltype(auto) operator()(Xs&& xs, F&& f) const { using S = typename hana::tag_of::type; using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, hana::Foldable::value ); #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Foldable::value, "hana::monadic_fold_left(xs, f) requires 'xs' to be Foldable"); #endif return MonadicFoldLeft::template apply(static_cast(xs), static_cast(f)); } }; namespace detail { struct foldlM_helper { template constexpr decltype(auto) operator()(F&& f, X&& x, K&& k, Z&& z) const { return hana::chain( static_cast(f)( static_cast(z), static_cast(x) ), static_cast(k) ); } }; template struct monadic_foldl1_helper { F f; template constexpr decltype(auto) operator()(X&& x, Y&& y) const { return f(static_cast(x), static_cast(y)); } template constexpr decltype(auto) operator()(End, Y&& y) const { return hana::lift(static_cast(y)); } }; } template struct monadic_fold_left_impl> : default_ { // with state template static constexpr decltype(auto) apply(Xs&& xs, S&& s, F&& f) { return hana::fold_right( static_cast(xs), hana::lift, hana::curry<3>(hana::partial( detail::foldlM_helper{}, static_cast(f) )) )(static_cast(s)); } // without state template static constexpr decltype(auto) apply(Xs&& xs, F&& f) { struct end { }; using G = detail::monadic_foldl1_helper::type>; decltype(auto) result = hana::monadic_fold_left( static_cast(xs), end{}, G{static_cast(f)} ); static_assert(!std::is_same< std::remove_reference_t, decltype(hana::lift(end{})) >{}, "hana::monadic_fold_left(xs, f) requires 'xs' to be non-empty"); return result; } }; BOOST_HANA_NAMESPACE_END #endif // !BOOST_HANA_MONADIC_FOLD_LEFT_HPP