From 14f890b4b2b9a640cab7e3687ef7bbca85ecf935 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sat, 26 Jul 2014 16:24:59 -0400 Subject: [PATCH] Iterable: refactor docs and make FoldableInstance a detail of implementation --- example/iterable/at.cpp | 19 +++ example/iterable/drop.cpp | 23 +++ example/iterable/drop_until.cpp | 30 ++++ example/iterable/drop_while.cpp | 30 ++++ example/iterable/for_each.cpp | 23 +++ example/iterable/head.cpp | 16 ++ example/iterable/is_empty.cpp | 17 ++ example/iterable/last.cpp | 16 ++ example/iterable/tail.cpp | 18 ++ include/boost/hana/detail/minimal/list.hpp | 3 +- include/boost/hana/ext/boost/fusion.hpp | 5 +- include/boost/hana/ext/boost/tuple.hpp | 1 - include/boost/hana/ext/std/array.hpp | 1 - .../boost/hana/ext/std/integer_sequence.hpp | 1 - include/boost/hana/ext/std/list.hpp | 1 - include/boost/hana/ext/std/tuple.hpp | 1 - include/boost/hana/integer_list.hpp | 1 - include/boost/hana/iterable.hpp | 1 - .../boost/hana/iterable/foldable_instance.hpp | 90 ---------- include/boost/hana/iterable/iterable.hpp | 155 ++++++++++++++---- include/boost/hana/iterable/mcd.hpp | 71 ++++++++ include/boost/hana/list/instance.hpp | 3 +- include/boost/hana/range.hpp | 3 +- include/boost/hana/type_list.hpp | 1 - test/sandbox/repeat.cpp | 1 - 25 files changed, 394 insertions(+), 137 deletions(-) create mode 100644 example/iterable/at.cpp create mode 100644 example/iterable/drop.cpp create mode 100644 example/iterable/drop_until.cpp create mode 100644 example/iterable/drop_while.cpp create mode 100644 example/iterable/for_each.cpp create mode 100644 example/iterable/head.cpp create mode 100644 example/iterable/is_empty.cpp create mode 100644 example/iterable/last.cpp create mode 100644 example/iterable/tail.cpp delete mode 100644 include/boost/hana/iterable/foldable_instance.hpp diff --git a/example/iterable/at.cpp b/example/iterable/at.cpp new file mode 100644 index 000000000..d5aa9a794 --- /dev/null +++ b/example/iterable/at.cpp @@ -0,0 +1,19 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT(at(int_<0>, list(0, '1', 2.0)) == 0); + BOOST_HANA_STATIC_ASSERT(at(int_<1>, list(0, '1', 2.0)) == '1'); + BOOST_HANA_STATIC_ASSERT(at(int_<2>, list(0, '1', 2.0)) == 2.0); + //! [main] +} diff --git a/example/iterable/drop.cpp b/example/iterable/drop.cpp new file mode 100644 index 000000000..23e72f2ff --- /dev/null +++ b/example/iterable/drop.cpp @@ -0,0 +1,23 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto xs = list(0, '1', 2.0); + BOOST_HANA_STATIC_ASSERT(drop(int_<0>, xs) == xs); + BOOST_HANA_STATIC_ASSERT(drop(int_<1>, xs) == list('1', 2.0)); + BOOST_HANA_STATIC_ASSERT(drop(int_<2>, xs) == list(2.0)); + BOOST_HANA_STATIC_ASSERT(drop(int_<3>, xs) == list()); + BOOST_HANA_STATIC_ASSERT(drop(int_<4>, xs) == list()); + //! [main] +} diff --git a/example/iterable/drop_until.cpp b/example/iterable/drop_until.cpp new file mode 100644 index 000000000..b970f5da0 --- /dev/null +++ b/example/iterable/drop_until.cpp @@ -0,0 +1,30 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +using namespace boost::hana; +using namespace literals; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto positive = [](auto x) { + return x > int_<0>; + }; + + BOOST_HANA_STATIC_ASSERT( + drop_until(positive, range(int_<-3>, int_<6>)) == range(int_<1>, int_<6>) + ); + + BOOST_HANA_STATIC_ASSERT( + drop_until(positive, list(1_c, -2_c, 4_c, 5_c)) == list(1_c, -2_c, 4_c, 5_c) + ); + //! [main] +} diff --git a/example/iterable/drop_while.cpp b/example/iterable/drop_while.cpp new file mode 100644 index 000000000..fc2ba7107 --- /dev/null +++ b/example/iterable/drop_while.cpp @@ -0,0 +1,30 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +using namespace boost::hana; +using namespace literals; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto negative = [](auto x) { + return x < int_<0>; + }; + + BOOST_HANA_STATIC_ASSERT( + drop_while(negative, range(int_<-3>, int_<6>)) == range(int_<0>, int_<6>) + ); + + BOOST_HANA_STATIC_ASSERT( + drop_while(negative, list(1_c, -2_c, 4_c, 5_c)) == list(1_c, -2_c, 4_c, 5_c) + ); + //! [main] +} diff --git a/example/iterable/for_each.cpp b/example/iterable/for_each.cpp new file mode 100644 index 000000000..50abf4cee --- /dev/null +++ b/example/iterable/for_each.cpp @@ -0,0 +1,23 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include + +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + std::stringstream ss; + for_each(list(0, '1', "234", 5.5), [&](auto x) { + ss << x << ' '; + }); + + assert(ss.str() == "0 1 234 5.5 "); + //! [main] +} diff --git a/example/iterable/head.cpp b/example/iterable/head.cpp new file mode 100644 index 000000000..ef814e172 --- /dev/null +++ b/example/iterable/head.cpp @@ -0,0 +1,16 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT(head(list(1, '2', 3.3, nullptr)) == 1); + //! [main] +} diff --git a/example/iterable/is_empty.cpp b/example/iterable/is_empty.cpp new file mode 100644 index 000000000..d7330e203 --- /dev/null +++ b/example/iterable/is_empty.cpp @@ -0,0 +1,17 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT(!is_empty(list(1, '2'))); + BOOST_HANA_STATIC_ASSERT( is_empty(list())); + //! [main] +} diff --git a/example/iterable/last.cpp b/example/iterable/last.cpp new file mode 100644 index 000000000..37e425b8a --- /dev/null +++ b/example/iterable/last.cpp @@ -0,0 +1,16 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT(last(list(1, '2', 3.3, nullptr)) == nullptr); + //! [main] +} diff --git a/example/iterable/tail.cpp b/example/iterable/tail.cpp new file mode 100644 index 000000000..0011d6c22 --- /dev/null +++ b/example/iterable/tail.cpp @@ -0,0 +1,18 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include +#include +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT( + tail(list(1, '2', 3.3, nullptr)) == list('2', 3.3, nullptr) + ); + //! [main] +} diff --git a/include/boost/hana/detail/minimal/list.hpp b/include/boost/hana/detail/minimal/list.hpp index e6017f0a4..65847a1f2 100644 --- a/include/boost/hana/detail/minimal/list.hpp +++ b/include/boost/hana/detail/minimal/list.hpp @@ -12,7 +12,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include -#include #include #include @@ -43,7 +42,7 @@ namespace detail { namespace minimal { template struct Foldable::instance> - : Iterable::FoldableInstance + : detail::FoldableFromIterable { }; template diff --git a/include/boost/hana/ext/boost/fusion.hpp b/include/boost/hana/ext/boost/fusion.hpp index bf499ed0a..3d192976b 100644 --- a/include/boost/hana/ext/boost/fusion.hpp +++ b/include/boost/hana/ext/boost/fusion.hpp @@ -15,7 +15,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include @@ -89,7 +88,7 @@ namespace boost { namespace hana { template <> struct Foldable::instance - : Iterable::FoldableInstance + : detail::FoldableFromIterable { template static constexpr decltype(auto) foldl_impl(F f, State s, Xs&& xs) { @@ -116,7 +115,7 @@ namespace boost { namespace hana { > > static constexpr decltype(auto) foldr_impl(F f, State s, Xs&& xs, ...) { - return Iterable::FoldableInstance::foldr_impl(f, s, std::forward(xs)); + return detail::FoldableFromIterable::foldr_impl(f, s, std::forward(xs)); } template diff --git a/include/boost/hana/ext/boost/tuple.hpp b/include/boost/hana/ext/boost/tuple.hpp index 32c5c6658..47e5fab3c 100644 --- a/include/boost/hana/ext/boost/tuple.hpp +++ b/include/boost/hana/ext/boost/tuple.hpp @@ -12,7 +12,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include -#include #include #include diff --git a/include/boost/hana/ext/std/array.hpp b/include/boost/hana/ext/std/array.hpp index 301912480..f2c797c28 100644 --- a/include/boost/hana/ext/std/array.hpp +++ b/include/boost/hana/ext/std/array.hpp @@ -13,7 +13,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include #include diff --git a/include/boost/hana/ext/std/integer_sequence.hpp b/include/boost/hana/ext/std/integer_sequence.hpp index 4eb47c45b..8167f3948 100644 --- a/include/boost/hana/ext/std/integer_sequence.hpp +++ b/include/boost/hana/ext/std/integer_sequence.hpp @@ -14,7 +14,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include diff --git a/include/boost/hana/ext/std/list.hpp b/include/boost/hana/ext/std/list.hpp index 4f6f9fbb0..88efe336a 100644 --- a/include/boost/hana/ext/std/list.hpp +++ b/include/boost/hana/ext/std/list.hpp @@ -12,7 +12,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include -#include #include #include diff --git a/include/boost/hana/ext/std/tuple.hpp b/include/boost/hana/ext/std/tuple.hpp index c6e2ab691..d621dc363 100644 --- a/include/boost/hana/ext/std/tuple.hpp +++ b/include/boost/hana/ext/std/tuple.hpp @@ -14,7 +14,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include #include diff --git a/include/boost/hana/integer_list.hpp b/include/boost/hana/integer_list.hpp index 09c8a13df..05e08a64d 100644 --- a/include/boost/hana/integer_list.hpp +++ b/include/boost/hana/integer_list.hpp @@ -11,7 +11,6 @@ Distributed under the Boost Software License, Version 1.0. #define BOOST_HANA_INTEGER_LIST_HPP #include -#include #include #include diff --git a/include/boost/hana/iterable.hpp b/include/boost/hana/iterable.hpp index dde82af9d..fa8e87685 100644 --- a/include/boost/hana/iterable.hpp +++ b/include/boost/hana/iterable.hpp @@ -10,7 +10,6 @@ Distributed under the Boost Software License, Version 1.0. #ifndef BOOST_HANA_ITERABLE_HPP #define BOOST_HANA_ITERABLE_HPP -#include #include #include diff --git a/include/boost/hana/iterable/foldable_instance.hpp b/include/boost/hana/iterable/foldable_instance.hpp deleted file mode 100644 index de8846f94..000000000 --- a/include/boost/hana/iterable/foldable_instance.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/*! -@file -Defines `boost::hana::Iterable::FoldableInstance`. - -@todo -Fix headers including this. One possibility would be to provide the instance -for Foldable when both foldable.hpp and iterable.hpp are included. - -@copyright Louis Dionne 2014 -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_ITERABLE_FOLDABLE_INSTANCE_HPP -#define BOOST_HANA_ITERABLE_FOLDABLE_INSTANCE_HPP - -#include - -#include // for instantiates -#include -#include - - -namespace boost { namespace hana { - struct Iterable::FoldableInstance : Foldable::mcd { - template - static constexpr auto foldl_impl(F f, State s, Iterable xs) { - return eval_if(is_empty(xs), - [=](auto) { return s; }, - [=](auto _) { return foldl_impl(f, f(s, head(_(xs))), tail(_(xs))); } - ); - } - - template - static constexpr auto foldl1_impl(F f, Iterable xs) - { return foldl(f, head(xs), tail(xs)); } - - template - static constexpr auto foldr1_impl(F f, Iterable xs) { - return eval_if(is_empty(tail(xs)), - [=](auto) { return head(xs); }, - [=](auto _) { return f(head(xs), foldr1_impl(f, tail(_(xs)))); } - ); - } - - template - static constexpr auto foldr_impl(F f, State s, Iterable xs) { - return eval_if(is_empty(xs), - [=](auto) { return s; }, - [=](auto _) { return f(head(_(xs)), foldr_impl(f, s, tail(_(xs)))); } - ); - } - }; - - //! @details - //! Let `xs` be an `Iterable` and let `xi` denote its `i`-th element. In - //! other words, `xs` can be folded into a list containing `[x1, ..., xN]`, - //! where `N` is the number of elements. Right-folding `xs` with a binary - //! operation `*` (in infix notation for legibility) is equivalent to - //! @code - //! x1 * (x2 * ( ... * (xN-1 * xN))) - //! @endcode - //! - //! Similarly, left-folding `xs` is equivalent to - //! @code - //! (((x1 * x2) * x3) * ...) * xN - //! @endcode - //! - //! In both cases, notice the side of the parentheses. Left-folding - //! applies `*` in a left-associative manner, whereas right-folding - //! applies it in a right-associative manner. For associative operations, - //! i.e. operations such that for all `a`, `b` and `c`, - //! @f{align*}{ - //! (a * b) * c = a * (b * c) - //! @f} - //! this makes no difference. Also note that lazy folds and folds with an - //! initial state are implemented in an analogous way. - //! - //! ### Example 1 - //! @snippet example/list/foldable/foldl.cpp main - //! - //! ### Example 2 - //! @snippet example/integer_list/foldable/foldr.cpp main - template - struct Foldable::instance()>> - : Iterable::FoldableInstance - { }; -}} // end namespace boost::hana - -#endif // !BOOST_HANA_ITERABLE_FOLDABLE_INSTANCE_HPP diff --git a/include/boost/hana/iterable/iterable.hpp b/include/boost/hana/iterable/iterable.hpp index 3de73316d..e6fe78117 100644 --- a/include/boost/hana/iterable/iterable.hpp +++ b/include/boost/hana/iterable/iterable.hpp @@ -15,23 +15,38 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { + namespace detail { + struct FoldableFromIterable; + } + //! @ingroup typeclasses - //! Data structures allowing external iteration. + //! `Iterable` represents data structures supporting external iteration. //! - //! @note - //! In the description of the methods, all indexing is 0-based. + //! ### Laws + //! In a sense, `Foldable` represents data structures supporting internal + //! iteration with the ability to accumulate a result. We request that + //! instances of both `Iterable` and `Foldable` provide consistent + //! instances. Hence, for any finite `Iterable` _and_ `Foldable` `it`, + //! the following laws must be satisfied: + //! @code + //! head(it) == head(to(it)) + //! to(tail(it)) == tail(to(it)) + //! is_empty(it) if and only if is_empty(to(it)) + //! @endcode //! - //! @todo - //! - What about infinite `Iterable`s? - //! - There are probably tons of laws that must be respected? + //! This is basically saying that linearizing a `Foldable` and then + //! iterating through it should be equivalent to iterating through it + //! in the first place. struct Iterable { BOOST_HANA_TYPECLASS(Iterable); struct mcd; - struct FoldableInstance; }; //! Return the first element of a non-empty iterable. - //! @method{Iterable} + //! @relates Iterable + //! + //! ### Example + //! @snippet example/iterable/head.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto head = [](auto iterable) { return Iterable::instance< datatype_t @@ -40,7 +55,10 @@ namespace boost { namespace hana { //! Return a new iterable containing all but the first element of a //! non-empty iterable. - //! @method{Iterable} + //! @relates Iterable + //! + //! ### Example + //! @snippet example/iterable/tail.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto tail = [](auto iterable) { return Iterable::instance< datatype_t @@ -48,7 +66,10 @@ namespace boost { namespace hana { }; //! Return whether the iterable is empty. - //! @method{Iterable} + //! @relates Iterable + //! + //! ### Example + //! @snippet example/iterable/is_empty.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto is_empty = [](auto iterable) { return Iterable::instance< datatype_t @@ -56,18 +77,31 @@ namespace boost { namespace hana { }; //! Return the `n`th element of an iterable. - //! @method{Iterable} + //! @relates Iterable + //! + //! + //! @param n + //! A non-negative `Integral` representing the 0-based index of the + //! element to return. The iterable must contain at least `n + 1` + //! elements. + //! + //! @param iterable + //! The iterable in which an element is fetched. + //! //! //! ### Example - //! @snippet example/list/iterable/at.cpp main + //! @snippet example/iterable/at.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto at = [](auto n, auto iterable) { return Iterable::instance< datatype_t >::at_impl(n, iterable); }; - //! Return the last element of a non-empty iterable. - //! @method{Iterable} + //! Return the last element of a non-empty and finite iterable. + //! @relates Iterable + //! + //! ### Example + //! @snippet example/iterable/last.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto last = [](auto iterable) { return Iterable::instance< datatype_t @@ -75,53 +109,116 @@ namespace boost { namespace hana { }; //! Drop the first `n` elements of an iterable and return the rest. - //! @method{Iterable} + //! @relates Iterable + //! + //! + //! @param n + //! A non-negative `Integral` representing the number of elements to be + //! dropped from the iterable. If `n` is greater than the number of + //! elements in the iterable, the returned iterable is empty. + //! + //! @param iterable + //! The iterable from which elements are dropped. //! - //! `n` must be a non-negative `Integral` representing the number of - //! elements to be dropped from the iterable. If `n` is greater than - //! the length of the iterable, the returned iterable is empty. //! //! ### Example - //! @snippet example/list/iterable/drop.cpp main + //! @snippet example/iterable/drop.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto drop = [](auto n, auto iterable) { return Iterable::instance< datatype_t >::drop_impl(n, iterable); }; - //! Drop elements from an iterable up to, but not including, the first + //! Drop elements from an iterable up to, but excluding, the first //! element for which the `predicate` is not satisfied. - //! @method{Iterable} + //! @relates Iterable //! //! Specifically, `drop_while` returns an iterable containing all the //! elements of the original iterable except for those in the range //! delimited by [`head`, `e`), where `head` is the first element and //! `e` is the first element for which the `predicate` is not satisfied. + //! If the iterable is not finite, the `predicate` has to return a false- + //! valued `Logical` at a finite index for this method to return. + //! + //! + //! @param predicate + //! A function called as `predicate(x)`, where `x` is an element of the + //! structure, and returning a `Logical` representing whether `x` should + //! be dropped from the structure. In the current version of the library, + //! `predicate` should return a [compile-time](@ref Logical_terminology) + //! `Logical`. + //! + //! @param iterable + //! The iterable from which elements are dropped. + //! //! //! ### Example - //! @snippet example/range/iterable/drop_while.cpp main + //! @snippet example/iterable/drop_while.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto drop_while = [](auto predicate, auto iterable) { return Iterable::instance< datatype_t >::drop_while_impl(predicate, iterable); }; - //! Equivalent to `drop_while` with a negated `predicate`. - //! @method{Iterable} + //! Drop elements from an iterable up to, but excluding, the first + //! element for which the `predicate` is satisfied. + //! @relates Iterable + //! + //! Specifically, `drop_until` returns an iterable containing all the + //! elements of the original iterable except for those in the range + //! delimited by [`head`, `e`), where `head` is the first element and + //! `e` is the first element for which the `predicate` is satisfied. + //! If the iterable is not finite, the `predicate` has to return a true- + //! valued `Logical` at a finite index for this method to return. + //! + //! @note + //! This is effectively equivalent to `drop_while` with a negated + //! `predicate`. + //! + //! + //! @param predicate + //! A function called as `predicate(x)`, where `x` is an element of the + //! structure, and returning a `Logical` representing whether `x` and + //! subsequent elements should be kept in the structure. In the current + //! version of the library, `predicate` should return a + //! [compile-time](@ref Logical_terminology) `Logical`. + //! + //! @param iterable + //! The iterable from which elements are dropped. + //! + //! + //! ### Example + //! @snippet example/iterable/drop_until.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto drop_until = [](auto predicate, auto iterable) { return Iterable::instance< datatype_t >::drop_until_impl(predicate, iterable); }; - //! Perform an action on each element of the iterable, discarding the - //! result each time. - //! @method{Iterable} + //! Perform an action on each element of an iterable, discarding + //! the result each time. + //! @relates Iterable + //! + //! Iteration is done in the same order as per repeatedly applying + //! `tail` to the iterable. If the iterable is not finite, this method + //! will not terminate. + //! + //! + //! @param iterable + //! The structure on which iteration is done. + //! + //! @param f + //! A function called as `f(x)` for each element `x` of the iterable. + //! The result of `f(x)`, whatever it is, is ignored. + //! //! //! ### Example - //! @snippet example/list/iterable/for_each.cpp main + //! @snippet example/iterable/for_each.cpp main //! - //! @todo This should probably be in a future `Traversable` type class. + //! @todo + //! The presence of implicit side effects in this function might be a + //! smell that it should be moved to a different type class and handled + //! through `Monad`s. BOOST_HANA_CONSTEXPR_LAMBDA auto for_each = [](auto iterable, auto f) { return Iterable::instance< datatype_t diff --git a/include/boost/hana/iterable/mcd.hpp b/include/boost/hana/iterable/mcd.hpp index ce2338d48..f6b1ea10a 100644 --- a/include/boost/hana/iterable/mcd.hpp +++ b/include/boost/hana/iterable/mcd.hpp @@ -13,6 +13,8 @@ Distributed under the Boost Software License, Version 1.0. #include #include +#include // for instantiates +#include #include #include @@ -73,6 +75,75 @@ namespace boost { namespace hana { ); } }; + + namespace detail { + struct FoldableFromIterable : Foldable::mcd { + template + static constexpr auto foldl_impl(F f, State s, Iterable xs) { + return eval_if(is_empty(xs), + [=](auto) { return s; }, + [=](auto _) { return foldl_impl(f, f(s, head(_(xs))), tail(_(xs))); } + ); + } + + template + static constexpr auto foldl1_impl(F f, Iterable xs) + { return foldl(f, head(xs), tail(xs)); } + + template + static constexpr auto foldr1_impl(F f, Iterable xs) { + return eval_if(is_empty(tail(xs)), + [=](auto) { return head(xs); }, + [=](auto _) { return f(head(xs), foldr1_impl(f, tail(_(xs)))); } + ); + } + + template + static constexpr auto foldr_impl(F f, State s, Iterable xs) { + return eval_if(is_empty(xs), + [=](auto) { return s; }, + [=](auto _) { return f(head(_(xs)), foldr_impl(f, s, tail(_(xs)))); } + ); + } + }; + } + + //! Every `Iterable` instance gives rise to an instance of `Foldable`, + //! which is valid for all finite such `Iterable`s. + //! + //! @details + //! Let `xs` be an `Iterable` and let `xi` denote its `i`-th element. In + //! other words, `xs` can be folded into a list containing `[x1, ..., xN]`, + //! where `N` is the number of elements. Right-folding `xs` with a binary + //! operation `*` (in infix notation for legibility) is equivalent to + //! @code + //! x1 * (x2 * ( ... * (xN-1 * xN))) + //! @endcode + //! + //! Similarly, left-folding `xs` is equivalent to + //! @code + //! (((x1 * x2) * x3) * ...) * xN + //! @endcode + //! + //! In both cases, notice the side of the parentheses. Left-folding + //! applies `*` in a left-associative manner, whereas right-folding + //! applies it in a right-associative manner. For associative operations, + //! i.e. operations such that for all `a`, `b` and `c`, + //! @f{align*}{ + //! (a * b) * c = a * (b * c) + //! @f} + //! this makes no difference. Also note that lazy folds and folds with an + //! initial state are implemented in an analogous way. + //! + //! ### Example 1 + //! @snippet example/list/foldable/foldl.cpp main + //! + //! ### Example 2 + //! @snippet example/integer_list/foldable/foldr.cpp main + template + struct Foldable::instance()>> + : detail::FoldableFromIterable + { }; }} // end namespace boost::hana #endif // !BOOST_HANA_ITERABLE_MCD_HPP diff --git a/include/boost/hana/list/instance.hpp b/include/boost/hana/list/instance.hpp index ebe6e8a36..5a3f9c059 100644 --- a/include/boost/hana/list/instance.hpp +++ b/include/boost/hana/list/instance.hpp @@ -23,7 +23,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include #include @@ -58,7 +57,7 @@ namespace boost { namespace hana { //! @details //! Generic instance for `Iterable`s. template <> - struct Foldable::instance : Iterable::FoldableInstance { + struct Foldable::instance : detail::FoldableFromIterable { template static constexpr auto foldl_impl(F f, State s, Xs xs) { return xs.storage([=](auto ...xs) { diff --git a/include/boost/hana/range.hpp b/include/boost/hana/range.hpp index b8994d27f..6a5524210 100644 --- a/include/boost/hana/range.hpp +++ b/include/boost/hana/range.hpp @@ -14,7 +14,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include #include @@ -94,7 +93,7 @@ namespace boost { namespace hana { //! Generic instance for `Iterable`s. template <> - struct Foldable::instance : Iterable::FoldableInstance { + struct Foldable::instance : detail::FoldableFromIterable { template static constexpr auto unpack_helper(F f, From from, detail::std::integer_sequence) diff --git a/include/boost/hana/type_list.hpp b/include/boost/hana/type_list.hpp index 70624f753..77be29cfa 100644 --- a/include/boost/hana/type_list.hpp +++ b/include/boost/hana/type_list.hpp @@ -12,7 +12,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include -#include #include #include #include diff --git a/test/sandbox/repeat.cpp b/test/sandbox/repeat.cpp index 7fcba6450..16fc0b458 100644 --- a/test/sandbox/repeat.cpp +++ b/test/sandbox/repeat.cpp @@ -8,7 +8,6 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include #include #include #include