From 184bf94382bb4c6559fc10735734832b58492a2c Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sat, 26 Jul 2014 12:52:05 -0400 Subject: [PATCH] Foldable: refactor the documentation --- example/foldable/count.cpp | 36 +++++ example/foldable/foldl.cpp | 25 ++++ example/foldable/foldl1.cpp | 25 ++++ example/foldable/foldr.cpp | 25 ++++ example/foldable/foldr1.cpp | 25 ++++ example/foldable/length.cpp | 21 +++ example/foldable/maximum.cpp | 19 +++ example/foldable/maximum_by.cpp | 29 ++++ example/foldable/minimum.cpp | 19 +++ example/foldable/minimum_by.cpp | 29 ++++ example/foldable/product.cpp | 24 ++++ example/foldable/sum.cpp | 24 ++++ example/foldable/unpack.cpp | 30 ++++ example/foldable/unpack_idiom.cpp | 25 ++++ include/boost/hana/foldable/foldable.hpp | 175 ++++++++++++++++++----- 15 files changed, 497 insertions(+), 34 deletions(-) create mode 100644 example/foldable/count.cpp create mode 100644 example/foldable/foldl.cpp create mode 100644 example/foldable/foldl1.cpp create mode 100644 example/foldable/foldr.cpp create mode 100644 example/foldable/foldr1.cpp create mode 100644 example/foldable/length.cpp create mode 100644 example/foldable/maximum.cpp create mode 100644 example/foldable/maximum_by.cpp create mode 100644 example/foldable/minimum.cpp create mode 100644 example/foldable/minimum_by.cpp create mode 100644 example/foldable/product.cpp create mode 100644 example/foldable/sum.cpp create mode 100644 example/foldable/unpack.cpp create mode 100644 example/foldable/unpack_idiom.cpp diff --git a/example/foldable/count.cpp b/example/foldable/count.cpp new file mode 100644 index 000000000..3fef5ccdc --- /dev/null +++ b/example/foldable/count.cpp @@ -0,0 +1,36 @@ +/* +@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 +#include +#include +#include + +#include +using namespace boost::hana; +using namespace literals; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto odd = [](auto x) { + return x % 2_c != 0_c; + }; + + constexpr auto types = type_list; + constexpr auto ints = integer_list; + + BOOST_HANA_STATIC_ASSERT(count(odd, ints) == 2_c); + + BOOST_HANA_STATIC_ASSERT(count(trait, types) == 1_c); + BOOST_HANA_STATIC_ASSERT(count(_ == type, types) == 2_c); + BOOST_HANA_STATIC_ASSERT(count(_ == type, types) == 0_c); + //! [main] +} diff --git a/example/foldable/foldl.cpp b/example/foldable/foldl.cpp new file mode 100644 index 000000000..d47c24b3b --- /dev/null +++ b/example/foldable/foldl.cpp @@ -0,0 +1,25 @@ +/* +@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] + auto to_string = [](auto x) { return (std::ostringstream{} << x).str(); }; + + auto show = [=](auto x, auto y) { + return "(" + to_string(x) + " + " + to_string(y) + ")"; + }; + + assert(foldl(show, "1", list(2, "3", '4')) == "(((1 + 2) + 3) + 4)"); + //! [main] +} diff --git a/example/foldable/foldl1.cpp b/example/foldable/foldl1.cpp new file mode 100644 index 000000000..3786dd227 --- /dev/null +++ b/example/foldable/foldl1.cpp @@ -0,0 +1,25 @@ +/* +@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] + auto to_string = [](auto x) { return (std::ostringstream{} << x).str(); }; + + auto show = [=](auto x, auto y) { + return "(" + to_string(x) + " + " + to_string(y) + ")"; + }; + + assert(foldl1(show, list(1, "2", '3')) == "((1 + 2) + 3)"); + //! [main] +} diff --git a/example/foldable/foldr.cpp b/example/foldable/foldr.cpp new file mode 100644 index 000000000..d26064856 --- /dev/null +++ b/example/foldable/foldr.cpp @@ -0,0 +1,25 @@ +/* +@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] + auto to_string = [](auto x) { return (std::ostringstream{} << x).str(); }; + + auto show = [=](auto x, auto y) { + return "(" + to_string(x) + " + " + to_string(y) + ")"; + }; + + assert(foldr(show, "4", list(1, "2", '3')) == "(1 + (2 + (3 + 4)))"); + //! [main] +} diff --git a/example/foldable/foldr1.cpp b/example/foldable/foldr1.cpp new file mode 100644 index 000000000..bff80a9f5 --- /dev/null +++ b/example/foldable/foldr1.cpp @@ -0,0 +1,25 @@ +/* +@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] + auto to_string = [](auto x) { return (std::ostringstream{} << x).str(); }; + + auto show = [=](auto x, auto y) { + return "(" + to_string(x) + " + " + to_string(y) + ")"; + }; + + assert(foldr1(show, list(1, "2", '3')) == "(1 + (2 + 3))"); + //! [main] +} diff --git a/example/foldable/length.cpp b/example/foldable/length.cpp new file mode 100644 index 000000000..196866773 --- /dev/null +++ b/example/foldable/length.cpp @@ -0,0 +1,21 @@ +/* +@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(length(list()) == 0); + BOOST_HANA_STATIC_ASSERT(length(list(1, '2', 3.0)) == 3); + + BOOST_HANA_STATIC_ASSERT(length(nothing) == 0); + BOOST_HANA_STATIC_ASSERT(length(just('x')) == 1); + //! [main] +} diff --git a/example/foldable/maximum.cpp b/example/foldable/maximum.cpp new file mode 100644 index 000000000..9dc56d1e2 --- /dev/null +++ b/example/foldable/maximum.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( + maximum(integer_list) == int_<9> + ); + //! [main] +} diff --git a/example/foldable/maximum_by.cpp b/example/foldable/maximum_by.cpp new file mode 100644 index 000000000..6f4ff0b4b --- /dev/null +++ b/example/foldable/maximum_by.cpp @@ -0,0 +1,29 @@ +/* +@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; + + +//! [main] +template +struct storage { + char c[i]; +}; + +int main() { + BOOST_HANA_CONSTEXPR_LAMBDA auto size = [](auto x, auto y) { + return bool_<(sizeof(x) < sizeof(y))>; + }; + + auto max = maximum_by(size, list(storage<1>{}, storage<3>{}, storage<2>{})); + static_assert(std::is_same>::value, ""); +} +//! [main] diff --git a/example/foldable/minimum.cpp b/example/foldable/minimum.cpp new file mode 100644 index 000000000..9d78aed56 --- /dev/null +++ b/example/foldable/minimum.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( + minimum(integer_list) == int_<-4> + ); + //! [main] +} diff --git a/example/foldable/minimum_by.cpp b/example/foldable/minimum_by.cpp new file mode 100644 index 000000000..83258a411 --- /dev/null +++ b/example/foldable/minimum_by.cpp @@ -0,0 +1,29 @@ +/* +@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; + + +//! [main] +template +struct storage { + char c[i]; +}; + +int main() { + BOOST_HANA_CONSTEXPR_LAMBDA auto size = [](auto x, auto y) { + return bool_<(sizeof(x) < sizeof(y))>; + }; + + auto min = minimum_by(size, list(storage<1>{}, storage<3>{}, storage<2>{})); + static_assert(std::is_same>::value, ""); +} +//! [main] diff --git a/example/foldable/product.cpp b/example/foldable/product.cpp new file mode 100644 index 000000000..17029d2e3 --- /dev/null +++ b/example/foldable/product.cpp @@ -0,0 +1,24 @@ +/* +@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_STATIC_ASSERT( + product(range(int_<1>, int_<6>)) == int_<1 * 2 * 3 * 4 * 5> + ); + + BOOST_HANA_STATIC_ASSERT( + product(list(1, int_<3>, long_<-5>, 9)) == 1 * 3 * -5 * 9 + ); + //! [main] +} diff --git a/example/foldable/sum.cpp b/example/foldable/sum.cpp new file mode 100644 index 000000000..0e49b86ab --- /dev/null +++ b/example/foldable/sum.cpp @@ -0,0 +1,24 @@ +/* +@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_STATIC_ASSERT( + sum(range(int_<1>, int_<6>)) == int_<1 + 2 + 3 + 4 + 5> + ); + + BOOST_HANA_STATIC_ASSERT( + sum(list(1, int_<3>, long_<-5>, 9)) == 1 + 3 - 5 + 9 + ); + //! [main] +} diff --git a/example/foldable/unpack.cpp b/example/foldable/unpack.cpp new file mode 100644 index 000000000..d0ff8afbb --- /dev/null +++ b/example/foldable/unpack.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 +using namespace boost::hana; + + +int main() { + //! [main] + auto cheap_tie = [](auto& ...vars) { + return partial(unpack, [&vars...](auto ...values) { + // Using an initializer list sequences the assignments. + int dummy[] = {((vars = values), 0)...}; + (void)dummy; + }); + }; + int a = 0; + char b = '\0'; + double c = 0; + + cheap_tie(a, b, c)(list(1, '2', 3.3)); + assert(a == 1 && b == '2' && c == 3.3); + //! [main] +} diff --git a/example/foldable/unpack_idiom.cpp b/example/foldable/unpack_idiom.cpp new file mode 100644 index 000000000..95d96dd94 --- /dev/null +++ b/example/foldable/unpack_idiom.cpp @@ -0,0 +1,25 @@ +/* +@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 add = [](auto x, auto y) { + return x + y; + }; + + // Would be `boost::fusion::make_fused(add)` in Boost.Fusion. + BOOST_HANA_CONSTEXPR_LAMBDA auto add_seq = partial(unpack, add); + + BOOST_HANA_STATIC_ASSERT(add_seq(list(1, 2)) == add(1, 2)); + //! [main] +} diff --git a/include/boost/hana/foldable/foldable.hpp b/include/boost/hana/foldable/foldable.hpp index 6ff7c9dfd..b9c372910 100644 --- a/include/boost/hana/foldable/foldable.hpp +++ b/include/boost/hana/foldable/foldable.hpp @@ -18,19 +18,36 @@ namespace boost { namespace hana { //! @ingroup typeclasses //! Data structures that can be folded, i.e. summarized into //! a single value. + //! + //! Another way of seeing `Foldable`s is as data structures supporting + //! internal iteration with the ability to accumulate a result. However, + //! because C++ only supports eager evaluation, all instances of `Foldable` + //! must represent finite data structures. While this may seem overly + //! restrictive in comparison to the Haskell definition of `Foldable`, + //! a finer grained separation of type classes (see `Iterable` and + //! `Searchable`) should mitigate the issue. struct Foldable { BOOST_HANA_TYPECLASS(Foldable); struct mcd; }; //! Left-associative fold of a structure using a binary operation. - //! @method{Foldable} + //! @relates Foldable //! - //! ### Example 1 - //! @snippet example/list/foldable/foldl.cpp main //! - //! ### Example 2 - //! @snippet example/type_list/foldable/foldl.cpp main + //! @param f + //! A binary function called as `f(state, x)`, where `state` is the + //! result accumulated so far and `x` is an element in the structure. + //! + //! @param state + //! The initial value used for folding. + //! + //! @param foldable + //! The structure to fold. + //! + //! + //! ### Example + //! @snippet example/foldable/foldl.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto foldl = [](auto f, auto state, auto foldable) { return Foldable::instance< datatype_t @@ -38,13 +55,22 @@ namespace boost { namespace hana { }; //! Right-associative fold of a structure using a binary operation. - //! @method{Foldable} + //! @relates Foldable //! - //! ### Example 1 - //! @snippet example/list/foldable/foldr.cpp main //! - //! ### Example 2 - //! @snippet example/integer_list/foldable/foldr.cpp main + //! @param f + //! A binary function called as `f(x, state)`, where `state` is the + //! result accumulated so far and `x` is an element in the structure. + //! + //! @param state + //! The initial value used for folding. + //! + //! @param foldable + //! The structure to fold. + //! + //! + //! ### Example + //! @snippet example/foldable/foldr.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto foldr = [](auto f, auto state, auto foldable) { return Foldable::instance< datatype_t @@ -53,10 +79,19 @@ namespace boost { namespace hana { //! Variant of `foldr` that has no base case, and thus may only be //! applied to non-empty structures. - //! @method{Foldable} + //! @relates Foldable + //! + //! + //! @param f + //! A binary function called as `f(x, state)`, where `state` is the + //! result accumulated so far and `x` is an element in the structure. + //! + //! @param foldable + //! The structure to fold. + //! //! //! ### Example - //! @snippet example/list/foldable/foldr1.cpp main + //! @snippet example/foldable/foldr1.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto foldr1 = [](auto f, auto foldable) { return Foldable::instance< datatype_t @@ -65,10 +100,19 @@ namespace boost { namespace hana { //! Variant of `foldl` that has no base case, and thus may only be //! applied to non-empty structures. - //! @method{Foldable} + //! @relates Foldable + //! + //! + //! @param f + //! A binary function called as `f(state, x)`, where `state` is the + //! result accumulated so far and `x` is an element in the structure. + //! + //! @param foldable + //! The structure to fold. + //! //! //! ### Example - //! @snippet example/list/foldable/foldl1.cpp main + //! @snippet example/foldable/foldl1.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto foldl1 = [](auto f, auto foldable) { return Foldable::instance< datatype_t @@ -76,10 +120,10 @@ namespace boost { namespace hana { }; //! Return the number of elements in a finite structure. - //! @method{Foldable} + //! @relates Foldable //! //! ### Example - //! @snippet example/list/foldable/length.cpp main + //! @snippet example/foldable/length.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto length = [](auto foldable) { return Foldable::instance< datatype_t @@ -88,10 +132,20 @@ namespace boost { namespace hana { //! Return the least element of a non-empty structure with respect to //! a `predicate`. - //! @method{Foldable} + //! @relates Foldable + //! + //! + //! @param predicate + //! A function called as `predicate(x, y)`, where `x` and `y` are elements + //! of the structure. `predicate` should be a [strict weak ordering](@ref strict_weak_ordering) + //! on the elements of the structure and its return value should be a `Logical`. + //! + //! @param foldable + //! The structure to find the least element of. + //! //! //! ### Example - //! @snippet example/type_list/foldable/minimum_by.cpp main + //! @snippet example/foldable/minimum_by.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto minimum_by = [](auto predicate, auto foldable) { return Foldable::instance< datatype_t @@ -99,27 +153,43 @@ namespace boost { namespace hana { }; //! Return the least element of a non-empty structure. - //! @method{Foldable} + //! @relates Foldable //! //! ### Example - //! @snippet example/integer_list/foldable/minimum.cpp main + //! @snippet example/foldable/minimum.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto minimum = [](auto foldable) { return Foldable::instance< datatype_t >::minimum_impl(foldable); }; - //! Return the largest element of a non-empty structure with respect to + //! Return the greatest element of a non-empty structure with respect to //! a `predicate`. - //! @method{Foldable} + //! @relates Foldable + //! + //! + //! @param predicate + //! A function called as `predicate(x, y)`, where `x` and `y` are elements + //! of the structure. `predicate` should be a [strict weak ordering](@ref strict_weak_ordering) + //! on the elements of the structure and its return value should be a `Logical`. + //! + //! @param foldable + //! The structure to find the greatest element of. + //! + //! + //! ### Example + //! @snippet example/foldable/maximum_by.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto maximum_by = [](auto predicate, auto foldable) { return Foldable::instance< datatype_t >::maximum_by_impl(predicate, foldable); }; - //! Return the largest element of a non-empty structure. - //! @method{Foldable} + //! Return the greatest element of a non-empty structure. + //! @relates Foldable + //! + //! ### Example + //! @snippet example/foldable/maximum.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto maximum = [](auto foldable) { return Foldable::instance< datatype_t @@ -127,7 +197,15 @@ namespace boost { namespace hana { }; //! Compute the sum of the numbers of a structure. - //! @method{Foldable} + //! @relates Foldable + //! + //! It must be possible to perform `operator+` on any two adjacent + //! elements of the structure. The meaning of "adjacent" as used here + //! is that two elements of the structure `x` and `y` are adjacent if + //! and only if they are adjacent in `to(foldable)`. + //! + //! ### Example + //! @snippet example/foldable/sum.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto sum = [](auto foldable) { return Foldable::instance< datatype_t @@ -135,10 +213,15 @@ namespace boost { namespace hana { }; //! Compute the product of the numbers of a structure. - //! @method{Foldable} + //! @relates Foldable + //! + //! It must be possible to perform `operator*` on any two adjacent + //! elements of the structure. The meaning of "adjacent" as used here + //! is that two elements of the structure `x` and `y` are adjacent if + //! and only if they are adjacent in `to(foldable)`. //! //! ### Example - //! @snippet example/range/foldable/product.cpp main + //! @snippet example/foldable/product.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto product = [](auto foldable) { return Foldable::instance< datatype_t @@ -147,13 +230,20 @@ namespace boost { namespace hana { //! Return the number of elements in the structure for which the //! `predicate` is satisfied. - //! @method{Foldable} + //! @relates Foldable //! - //! ### Example 1 - //! @snippet example/integer_list/foldable/count.cpp main //! - //! ### Example 2 - //! @snippet example/type_list/foldable/count.cpp main + //! @param predicate + //! A function called as `predicate(x)`, where `x` is an element of the + //! structure, and returning a `Logical` representing whether `x` should + //! add `1` to the overall result. + //! + //! @param foldable + //! The structure whose elements are counted. + //! + //! + //! ### Example + //! @snippet example/foldable/count.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto count = [](auto predicate, auto foldable) { return Foldable::instance< datatype_t @@ -161,10 +251,27 @@ namespace boost { namespace hana { }; //! Invoke a function with the elements of a structure as arguments. - //! @method{Foldable} + //! @relates Foldable + //! + //! + //! @param f + //! A function to be invoked as `f(x...)`, where `x...` are the elements + //! of the structure as-if they had been linearized with `to`. + //! + //! @param foldable + //! The structure to expand into the function. + //! + //! + //! @note + //! This can be used to transform a function taking multiple arguments + //! to a function taking a `Foldable` by partially applying `unpack`: + //! @snippet example/foldable/unpack_idiom.cpp main + //! This idiom serves the role of `boost::fusion::make_fused` and + //! related utilities in the Boost.Fusion library. + //! //! //! ### Example - //! @snippet example/list/foldable/unpack.cpp main + //! @snippet example/foldable/unpack.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto unpack = [](auto f, auto foldable) { return Foldable::instance< datatype_t