monadic_fold_left.hpp 4.7 KB

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