diff --git a/example/list/applicative.cpp b/example/list/applicative.cpp new file mode 100644 index 000000000..e2a28cfd6 --- /dev/null +++ b/example/list/applicative.cpp @@ -0,0 +1,34 @@ +/* +@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 +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT(lift('x') == list('x')); + BOOST_HANA_STATIC_ASSERT(lift('x') == std::make_tuple('x')); + + BOOST_HANA_CONSTEXPR_LAMBDA auto f = pair; + BOOST_HANA_CONSTEXPR_LAMBDA auto g = flip(pair); + BOOST_HANA_STATIC_ASSERT( + ap(list(f, g), list(1, 2, 3), list('a', 'b')) + == + list( + f(1, 'a'), f(1, 'b'), f(2, 'a'), f(2, 'b'), f(3, 'a'), f(3, 'b'), + g(1, 'a'), g(1, 'b'), g(2, 'a'), g(2, 'b'), g(3, 'a'), g(3, 'b') + ) + ); + //! [main] +} diff --git a/example/list/concat.cpp b/example/list/concat.cpp index 5a5fc7d21..f9ad06ca3 100644 --- a/example/list/concat.cpp +++ b/example/list/concat.cpp @@ -13,6 +13,8 @@ using namespace literals; int main() { //! [main] - BOOST_HANA_STATIC_ASSERT(concat(list(1, '2'), list(3.3, 4_c)) == list(1, '2', 3.3, 4_c)); + BOOST_HANA_STATIC_ASSERT( + concat(list(1, '2'), list(3.3, 4_c)) == list(1, '2', 3.3, 4_c) + ); //! [main] } diff --git a/example/list/cons.cpp b/example/list/cons.cpp index 1313b5ace..5b9238151 100644 --- a/example/list/cons.cpp +++ b/example/list/cons.cpp @@ -12,7 +12,7 @@ using namespace boost::hana; int main() { //! [main] BOOST_HANA_STATIC_ASSERT(cons(1, list()) == list(1)); - BOOST_HANA_STATIC_ASSERT(cons(1, list('2', "3")) == list(1, '2', "3")); - BOOST_HANA_STATIC_ASSERT(cons(1, cons('2', cons("3", list()))) == list(1, '2', "3")); + BOOST_HANA_STATIC_ASSERT(cons(1, list('2', 3.3)) == list(1, '2', 3.3)); + BOOST_HANA_STATIC_ASSERT(cons(1, cons('2', cons(3.3, list()))) == list(1, '2', 3.3)); //! [main] } diff --git a/example/list/init.cpp b/example/list/init.cpp index d07b477a6..6d0a1844e 100644 --- a/example/list/init.cpp +++ b/example/list/init.cpp @@ -14,6 +14,6 @@ using namespace literals; int main() { //! [main] BOOST_HANA_STATIC_ASSERT(init(list(1)) == list()); - BOOST_HANA_STATIC_ASSERT(init(list(1, '2', "3", 4_c)) == list(1, '2', "3")); + BOOST_HANA_STATIC_ASSERT(init(list(1, '2', 3.3, 4_c)) == list(1, '2', 3.3)); //! [main] } diff --git a/example/list/into.cpp b/example/list/into.cpp index ba6d9c8b4..d4939177d 100644 --- a/example/list/into.cpp +++ b/example/list/into.cpp @@ -5,18 +5,13 @@ Distributed under the Boost Software License, Version 1.0. */ #include -#include #include -#include - -#include using namespace boost::hana; int main() { //! [main] - BOOST_HANA_STATIC_ASSERT(unpack(into, just(3)) == list(3)); - BOOST_HANA_STATIC_ASSERT(unpack(into, nothing) == list()); - BOOST_HANA_STATIC_ASSERT(unpack(into, std::make_tuple(1, '2', 3.3)) == list(1, '2', 3.3)); + BOOST_HANA_STATIC_ASSERT(into() == list()); + BOOST_HANA_STATIC_ASSERT(into(1, '2', 3.3) == list(1, '2', 3.3)); //! [main] } diff --git a/example/list/monad.cpp b/example/list/monad.cpp new file mode 100644 index 000000000..0112073ea --- /dev/null +++ b/example/list/monad.cpp @@ -0,0 +1,22 @@ +/* +@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_CONSTEXPR_LAMBDA auto f = [](auto x) { return list(x, -x); }; + + BOOST_HANA_STATIC_ASSERT((list(1, 2, 3) | f) == list(1, -1, 2, -2, 3, -3)); + + BOOST_HANA_STATIC_ASSERT( + flatten(list(list(1, 2), list(3, 4), list(list(5, 6)))) == list(1, 2, 3, 4, list(5, 6)) + ); + //! [main] +} diff --git a/example/list/nil.cpp b/example/list/nil.cpp new file mode 100644 index 000000000..92254d61a --- /dev/null +++ b/example/list/nil.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(nil == list()); + //! [main] +} diff --git a/example/list/partition.cpp b/example/list/partition.cpp new file mode 100644 index 000000000..521692477 --- /dev/null +++ b/example/list/partition.cpp @@ -0,0 +1,46 @@ +/* +@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; + + +int main() { + //! [ints] + BOOST_HANA_CONSTEXPR_LAMBDA auto odd = [](auto x) { + return x % int_<2> != int_<0>; + }; + + BOOST_HANA_STATIC_ASSERT( + partition(odd, integer_list) + == + pair( + integer_list, + integer_list + ) + ); + //! [ints] + + //! [types] + BOOST_HANA_STATIC_ASSERT( + partition(trait, type_list) + == + pair( + type_list, + type_list + ) + ); + //! [types] +} diff --git a/example/list/permutations.cpp b/example/list/permutations.cpp index 5645c2af7..d1d42a876 100644 --- a/example/list/permutations.cpp +++ b/example/list/permutations.cpp @@ -14,7 +14,7 @@ using namespace boost::hana; int main() { //! [main] BOOST_HANA_CONSTEXPR_LAMBDA auto is_permutation_of = curry<2>([](auto xs, auto perm) { - return any(_ == perm, permutations(xs)); + return elem(perm, permutations(xs)); }); BOOST_HANA_STATIC_ASSERT( diff --git a/example/list/take_until.cpp b/example/list/take_until.cpp new file mode 100644 index 000000000..d1cbcac09 --- /dev/null +++ b/example/list/take_until.cpp @@ -0,0 +1,22 @@ +/* +@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_STATIC_ASSERT( + take_until(_ < 2_c, integer_list) == integer_list + ); + //! [main] +} diff --git a/example/list/take_while.cpp b/example/list/take_while.cpp new file mode 100644 index 000000000..90d4c6d0d --- /dev/null +++ b/example/list/take_while.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 +#include +using namespace boost::hana; +using namespace literals; + + +int main() { + //! [main] + BOOST_HANA_STATIC_ASSERT( + take_while(_ < 2_c, integer_list) == integer_list + ); + //! [main] +} diff --git a/example/list/unfoldl.cpp b/example/list/unfoldl.cpp new file mode 100644 index 000000000..5d56f2306 --- /dev/null +++ b/example/list/unfoldl.cpp @@ -0,0 +1,26 @@ +/* +@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 +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto f = [](auto x) { + return if_(x == int_<0>, nothing, just(pair(x - int_<1>, x))); + }; + + BOOST_HANA_STATIC_ASSERT( + unfoldl(f, int_<10>) == integer_list + ); + //! [main] +} diff --git a/example/list/unfoldr.cpp b/example/list/unfoldr.cpp new file mode 100644 index 000000000..5f7a31739 --- /dev/null +++ b/example/list/unfoldr.cpp @@ -0,0 +1,26 @@ +/* +@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 +using namespace boost::hana; + + +int main() { + //! [main] + BOOST_HANA_CONSTEXPR_LAMBDA auto f = [](auto x) { + return if_(x == int_<0>, nothing, just(pair(x, x - int_<1>))); + }; + + BOOST_HANA_STATIC_ASSERT( + unfoldr(f, int_<10>) == integer_list + ); + //! [main] +} diff --git a/include/boost/hana/list/instance.hpp b/include/boost/hana/list/instance.hpp index 5a3f9c059..523897e2e 100644 --- a/include/boost/hana/list/instance.hpp +++ b/include/boost/hana/list/instance.hpp @@ -54,8 +54,7 @@ namespace boost { namespace hana { return list_detail::list{storage}; }; - //! @details - //! Generic instance for `Iterable`s. + //! @cond template <> struct Foldable::instance : detail::FoldableFromIterable { template @@ -84,6 +83,7 @@ namespace boost { namespace hana { }); } }; + //! @endcond //! @details //! `List` is an `Iterable` in the most obvious way. The head of a @@ -125,9 +125,7 @@ namespace boost { namespace hana { } }; - //! @details - //! `nil` is equivalent to `list()`, and `cons(x, list(xs...))` is - //! equivalent to `list(x, xs...)`. + //! Instance of `List` for the `List` data type. template <> struct List::instance : List::mcd { static BOOST_HANA_CONSTEXPR_LAMBDA auto nil_impl() { diff --git a/include/boost/hana/list/list.hpp b/include/boost/hana/list/list.hpp index 50242d098..323d6138c 100644 --- a/include/boost/hana/list/list.hpp +++ b/include/boost/hana/list/list.hpp @@ -16,44 +16,40 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - /*! - @ingroup typeclasses - @ingroup datatypes - General purpose index-based sequence. - - -------------------------------------------------------------------------- - - ## Instance of (as a data type) - `Iterable`, `Functor`, `Applicative`, `Monad`, `Foldable`, `Traversable`, - and `Comparable` - - -------------------------------------------------------------------------- - - ## Laws (as a type class) - For any two `List`s `x` and `y`, - @f{align*}{ - x = y \iff \tt{to(x)} = \tt{to(y)} - @f} - This is basically saying that all `List` instances are isomorphic, and - it therefore makes sense to define comparison for any two `List`s. - - -------------------------------------------------------------------------- - - @todo - - It might be possible to optimize the implementation of homogeneous lists - using an array. - - How to implement iterate and repeat? - - We could provide automatic unit testing for any instance because we - have the isomorphisms. - - There is a strong relationship between this and `MonadPlus`. Actually, - they might be just the same. Check this out. - - Implement the following methods: - - `intersperse`, `intercalate`, `transpose`, `subsequences` - - `split_at`, `span`, `break`, `group_by`, `group`, `inits`, `tails` - - Consider implementing the following methods: - - `nub_by`, `nub`, `delete_by`, `insert` - - `set_difference_by`, `set_union_by`, `set_intersection_by` - */ + //! @ingroup typeclasses + //! @ingroup datatypes + //! + //! General purpose index-based sequence. + //! + //! + //! ### Laws + //! For any two `List`s `xs` and `ys`, the following statement must hold: + //! + //! @code + //! xs == ys if and only if to(xs) == to(ys) + //! @endcode + //! + //! This is basically saying that all `List` instances are isomorphic to + //! the instance defined by the `List` data type, and it therefore makes + //! sense to define comparison for any two instances of `List`. + //! + //! + //! @todo + //! - It might be possible to optimize the implementation of homogeneous + //! lists using an array. + //! - How to implement iterate and repeat? + //! - We could provide automatic unit testing for any instance because we + //! have the isomorphisms. + //! - There is a strong relationship between this and `MonadPlus`. + //! Actually, they might be just the same. Check this out. + //! - Implement the following methods: + //! - `intersperse`, `intercalate`, `transpose`, `subsequences` + //! - `split_at`, `span`, `break`, `group_by`, `group`, `inits`, `tails` + //! - Consider implementing the following methods: + //! - `nub_by`, `nub`, `delete_by`, `insert` + //! - `set_difference_by`, `set_union_by`, `set_intersection_by` + //! - Since we can benchmark the isomorphic instances, put the benchmarks + //! in the documentation. struct List { BOOST_HANA_TYPECLASS(List); template @@ -61,7 +57,10 @@ namespace boost { namespace hana { }; //! Concatenate two lists together. - //! @method{List} + //! @relates List + //! + //! @param xs, ys + //! Two instances of `List` with _the same data type_. //! //! ### Example //! @snippet example/list/concat.cpp main @@ -76,7 +75,15 @@ namespace boost { namespace hana { }; //! Prepend an element to the head of a list. - //! @method{List} + //! @relates List + //! + //! + //! @param x + //! An element to prepend to the list. + //! + //! @param xs + //! The list to which an element is prepended. + //! //! //! ### Example //! @snippet example/list/cons.cpp main @@ -86,8 +93,20 @@ namespace boost { namespace hana { >::cons_impl(x, xs); }; - //! Return a list containing only the elements satisfying the `predicate`. - //! @method{List} + //! Return a list containing only the elements satisfying a `predicate`. + //! @relates List + //! + //! + //! @param predicate + //! A function called as `predicate(x)` for each element `x` in the list + //! and returning a `Logical` representing whether that element should be + //! __kept__ in the resulting list. In the current version of the library, + //! the `predicate` has to return a [compile-time](@ref Logical_terminology) + //! `Logical`. + //! + //! @param xs + //! The list to filter. + //! //! //! ### Example //! @snippet example/list/filter.cpp main @@ -97,8 +116,8 @@ namespace boost { namespace hana { >::filter_impl(predicate, xs); }; - //! Removes the last element of a non-empty list. - //! @method{List} + //! Remove the last element of a non-empty list. + //! @relates List //! //! ### Example //! @snippet example/list/init.cpp main @@ -117,34 +136,69 @@ namespace boost { namespace hana { }; } - //! Creates a `List` with the given elements in it. - //! @method{List} + //! Create a `List` with the given elements in it. + //! @relates List + //! + //! + //! @tparam L + //! The data type representing the `List` to create. This can be any + //! instance of the `List` type class. + //! + //! @param xs... + //! The elements to put in the constructed list. The elements will appear + //! in the resulting list in the same order as passed to `into`. + //! //! //! ### Example //! @snippet example/list/into.cpp main - template - constexpr list_detail::into into{}; +#ifdef BOOST_HANA_DOXYGEN_INVOKED + template + constexpr auto into = [](auto ...xs) { + return List::instance::into_impl(xs...); + }; +#else + template + constexpr list_detail::into into{}; +#endif - //! An empty list. - //! @method{List} - template - BOOST_HANA_CONSTEXPR_LAMBDA auto nil = List::instance::nil_impl(); + //! `nil` is an empty list of data type `L`. + //! @relates List + //! + //! @tparam L + //! The data type of the empty list wanted. This must be an instance of + //! the `List` type class. + //! + //! + //! ### Example + //! @snippet example/list/nil.cpp main + template + BOOST_HANA_CONSTEXPR_LAMBDA auto nil = List::instance::nil_impl(); //! Partition a list based on a `predicate`. - //! @method{List} + //! @relates List //! //! Specifically, returns a `Pair` whose first element is a list of the //! elements satisfying the predicate, and whose second element is a //! list of the elements that do not satisfy the predicate. //! - //! @note - //! The predicate must return an `Integral`. //! - //! ### Example 1 - //! @snippet example/integer_list/partition.cpp main + //! @param predicate + //! A function called as `predicate(x)` for each element `x` in the list + //! and returning a `Logical`. If the result of `predicate` is true-valued, + //! then `x` is added to the list in the first component of the resulting + //! `Pair`. Otherwise, `x` is added to the list in the second component. + //! In the current version of the library, the `predicate` has to return + //! a [compile-time](@ref Logical_terminology) `Logical`. //! - //! ### Example 2 - //! @snippet example/type_list/partition.cpp main + //! @param xs + //! The list to be partitioned. + //! + //! + //! ### Example + //! @snippet example/list/partition.cpp ints + //! + //! ### Example + //! @snippet example/list/partition.cpp types BOOST_HANA_CONSTEXPR_LAMBDA auto partition = [](auto predicate, auto xs) { return List::instance< datatype_t @@ -152,22 +206,22 @@ namespace boost { namespace hana { }; //! Return a list of all the permutations of the given list. - //! @method{List} + //! @relates List //! //! The permutations are not guaranteed to be in any specific order. //! + //! @note + //! Implementation taken from http://stackoverflow.com/a/2184129/627587. + //! //! ### Example //! @snippet example/list/permutations.cpp main //! //! ### Benchmarks //! @image html benchmark.list.permutations.time.png //! - //! @note - //! Implementation taken from http://stackoverflow.com/a/2184129/627587. - //! //! @bug //! We got a performance problem here. Generating the permutations of - //! a list of more than 3 elements starts taking a long time (>6s). + //! a list of more than 3 elements takes a long time (>6s). BOOST_HANA_CONSTEXPR_LAMBDA auto permutations = [](auto xs) { return List::instance< datatype_t @@ -175,7 +229,7 @@ namespace boost { namespace hana { }; //! Reverse a list. - //! @method{List} + //! @relates List //! //! ### Example //! @snippet example/list/reverse.cpp main @@ -186,21 +240,47 @@ namespace boost { namespace hana { }; //! Similar to `foldl`, but returns a list of reduced values from the left. - //! @method{List} + //! @relates List + //! + //! + //! @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 list. + //! + //! @param state + //! The initial value used for folding. This will always be the first + //! element of the resulting list. + //! + //! @param xs + //! The list to scan. + //! //! //! ### Example //! @snippet example/list/scanl.cpp main //! //! ### Benchmarks //! @image html benchmark.list.scanl.time.png - BOOST_HANA_CONSTEXPR_LAMBDA auto scanl = [](auto f, auto s, auto xs) { + BOOST_HANA_CONSTEXPR_LAMBDA auto scanl = [](auto f, auto state, auto xs) { return List::instance< datatype_t - >::scanl_impl(f, s, xs); + >::scanl_impl(f, state, xs); }; //! Variant of `scanl` that has no starting value argument. - //! @method{List} + //! @relates List + //! + //! While `foldl1` may not be called with an empty structure, `scanl1` + //! can be called with an empty list, in which case it will simply return + //! an empty list. + //! + //! + //! @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 list. + //! + //! @param xs + //! The list to scan. + //! //! //! ### Example //! @snippet example/list/scanl1.cpp main @@ -214,21 +294,47 @@ namespace boost { namespace hana { }; //! Similar to `foldr`, but returns a list of reduced values from the right. - //! @method{List} + //! @relates List + //! + //! + //! @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 list. + //! + //! @param state + //! The initial value used for folding. This will always be the last + //! element of the resulting list. + //! + //! @param xs + //! The list to scan. + //! //! //! ### Example //! @snippet example/list/scanr.cpp main //! //! ### Benchmarks //! @image html benchmark.list.scanr.time.png - BOOST_HANA_CONSTEXPR_LAMBDA auto scanr = [](auto f, auto s, auto xs) { + BOOST_HANA_CONSTEXPR_LAMBDA auto scanr = [](auto f, auto state, auto xs) { return List::instance< datatype_t - >::scanr_impl(f, s, xs); + >::scanr_impl(f, state, xs); }; //! Variant of `scanr` that has no starting value argument. - //! @method{List} + //! @relates List + //! + //! While `foldr1` may not be called with an empty structure, `scanr1` + //! can be called with an empty list, in which case it will simply return + //! an empty list. + //! + //! + //! @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 list. + //! + //! @param xs + //! The list to scan. + //! //! //! ### Example //! @snippet example/list/scanr1.cpp main @@ -242,7 +348,15 @@ namespace boost { namespace hana { }; //! Append an element to the end of a list. - //! @method{List} + //! @relates List + //! + //! + //! @param xs + //! The list to which an element is appended. + //! + //! @param x + //! An element to append to the list. + //! //! //! ### Example //! @snippet example/list/snoc.cpp main @@ -252,8 +366,13 @@ namespace boost { namespace hana { >::snoc_impl(xs, x); }; - //! Sort a list based on the `less` strict weak ordering. - //! @method{List} + //! Sort a list based on the `less` [strict weak ordering](@ref strict_weak_ordering). + //! @relates List + //! + //! The elements in the list must all be `Orderable`. In the current + //! version of the library, the `less` method of the `Orderable` + //! instance must be a [compile-time](@ref Logical_terminology) `Logical`. + //! //! //! ### Example //! @snippet example/list/sort.cpp main @@ -264,11 +383,24 @@ namespace boost { namespace hana { }; //! Sort a list based on the given `predicate`. - //! @method{List} + //! @relates List //! - //! The predicate must be a [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_ordering#Strict_weak_orderings). //! The sort is guaranteed to be stable. //! + //! + //! @param predicate + //! A function called as `predicate(x, y)` for two elements `x` and `y` of + //! the list, and returning a `Logical` representing whether `x` should + //! appear __before__ `y` in the resulting list. More specifically, the + //! `predicate` must define a [strict weak ordering](@ref strict_weak_ordering) + //! on the elements of the list. In the current version of the library, + //! `predicate` must return a [compile-time](@ref Logical_terminology) + //! `Logical` when called with any two elements of the list. + //! + //! @param xs + //! The list to sort. + //! + //! //! ### Example //! @snippet example/list/sort_by.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto sort_by = [](auto predicate, auto xs) { @@ -277,12 +409,18 @@ namespace boost { namespace hana { >::sort_by_impl(predicate, xs); }; - //! Return the first `n` elements of a list. - //! @method{List} + //! Return a list containing the first `n` elements of a list. + //! @relates List + //! + //! + //! @param n + //! A non-negative `Integral` representing the number of elements to keep + //! in the resulting list. If `n` is greater than the length of the input + //! list, the whole list is returned. + //! + //! @param xs + //! The list to take the elements from. //! - //! `n` must be a non-negative `Integral` representing the number of - //! elements to keep. If `n` is greater than the length of the list, - //! the whole list is returned. //! //! ### Example //! @snippet example/list/take.cpp main @@ -293,12 +431,26 @@ namespace boost { namespace hana { }; //! Take elements until the `predicate` is satisfied. - //! @method{List} + //! @relates List + //! + //! Specifically, returns the longest prefix of a list in which all + //! elements do not satisfy the predicate. This is effectively equivalent + //! to `take_while` with a negated predicate. + //! + //! + //! @param predicate + //! A function called as `predicate(x)`, where `x` is an element of the + //! list, and returning a `Logical` representing whether the resulting + //! list should stop at the element before `x`. In the current version + //! of the library, `predicate` has to return a + //! [compile-time](@ref Logical_terminology) `Logical`. + //! + //! @param xs + //! The list to take the elements from. //! - //! This is equivalent to `take_while` with a negated predicate. //! //! ### Example - //! @snippet example/integer_list/take_until.cpp main + //! @snippet example/list/take_until.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto take_until = [](auto predicate, auto xs) { return List::instance< datatype_t @@ -306,14 +458,25 @@ namespace boost { namespace hana { }; //! Take elements while the `predicate` is satisfied. - //! @method{List} + //! @relates List //! //! Specifically, returns the longest prefix of a list in which all - //! elements satisfy the given predicate. The predicate must return - //! an `Integral`. + //! elements satisfy the given predicate. + //! + //! + //! @param predicate + //! A function called as `predicate(x)`, where `x` is an element of the + //! list, and returning a `Logical` representing whether `x` should be + //! included in the resulting list. In the current version of the library, + //! `predicate` has to return a [compile-time](@ref Logical_terminology) + //! `Logical`. + //! + //! @param xs + //! The list to take elements from. + //! //! //! ### Example - //! @snippet example/integer_list/take_while.cpp main + //! @snippet example/list/take_while.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto take_while = [](auto predicate, auto xs) { return List::instance< datatype_t @@ -337,59 +500,106 @@ namespace boost { namespace hana { } //! Dual to `foldl` for lists. - //! @method{List} + //! @relates List //! //! While `foldl` reduces a list to a summary value, `unfoldl` builds a - //! list from a seed value and a function. The function takes the initial - //! value and returns `nothing` if it is done producing the list, and - //! `just(P(init, elem))` otherwise, where `P` is an arbitrary `Pair` - //! constructor and `elem` is the produced element which is appended to - //! the list and `init` is the new initial value used in a recursive call - //! to the function. - //! - //! In some cases, `unfoldl` can undo a `foldl` operation: + //! list from a seed value and a function. In some cases, `unfoldl` can + //! undo a `foldl` operation: //! @code //! unfoldl(g, foldl(f, z, xs)) //! @endcode + //! //! if the following holds //! @code //! g(f(y, x)) == just(pair(y, x)) //! g(z) == nothing //! @endcode //! + //! + //! @param f + //! A function called as `f(init)`, where `init` is an initial value, + //! and returning + //! 1. `nothing` if it is done producing the list. + //! 2. `just(pair(init, x))` if it isn't, where `init` is the new + //! initial value used in the next call to `f` and `x` is an + //! element to be appended to the resulting list. Also note + //! that `pair` may actually be replaced by any instance of + //! the `Pair` type class. + //! + //! @param init + //! An initial value to build the list from. + //! + //! //! ### Example - //! @snippet example/integer_list/unfoldl.cpp main + //! @snippet example/list/unfoldl.cpp main +#ifdef BOOST_HANA_DOXYGEN_INVOKED + template + constexpr auto unfoldl = [](auto f, auto init) { + return List::instance::unfoldl_impl(f, init); + }; +#else template constexpr list_detail::unfoldl unfoldl{}; +#endif //! Dual to `foldr` for lists. - //! @method{List} + //! @relates List //! //! While `foldr` reduces a list to a summary value, `unfoldr` builds a - //! list from a seed value and a function. The function takes the initial - //! value and returns `nothing` if it is done producing the list, and - //! `just(P(elem, init))` otherwise, where `P` is an arbitrary `Pair` - //! constructor and `elem` is the produced element which is prepended to - //! the list and `init` is the new initial value used in a recursive call - //! to the function. - //! - //! In some cases, `unfoldr` can undo a `foldr` operation: + //! list from a seed value and a function. In some cases, `unfoldr` can + //! undo a `foldr` operation: //! @code //! unfoldr(g, foldr(f, z, xs)) //! @endcode + //! //! if the following holds //! @code //! g(f(x, y)) == just(pair(x, y)) //! g(z) == nothing //! @endcode //! + //! + //! @param f + //! A function called as `f(init)`, where `init` is an initial value, + //! and returning + //! 1. `nothing` if it is done producing the list. + //! 2. `just(pair(x, init))` if it isn't, where `init` is the new + //! initial value used in a recursive call to `f` and `x` is an + //! element prepended to the resulting list. Also note that `pair` + //! may actually be replaced by any instance of the `Pair` type + //! class. + //! + //! @param init + //! An initial value to build the list from. + //! + //! //! ### Example - //! @snippet example/integer_list/unfoldr.cpp main + //! @snippet example/list/unfoldr.cpp main +#ifdef BOOST_HANA_DOXYGEN_INVOKED + template + constexpr auto unfoldr = [](auto f, auto init) { + return List::instance::unfoldr_impl(f, init); + }; +#else template constexpr list_detail::unfoldr unfoldr{}; +#endif + //! Unzip a list of lists. - //! @method{List} + //! @relates List + //! + //! Specifically, takes a list of the form + //! @code + //! [s1, s2, ..., sn] + //! @endcode + //! where each `si` is a list, and returns a list equivalent to + //! `zip(s1, s2, ..., sn)`. + //! + //! + //! @param xs + //! A list of lists to unzip. + //! //! //! ### Example //! @snippet example/list/unzip.cpp main @@ -400,7 +610,13 @@ namespace boost { namespace hana { }; //! Zip one list or more. - //! @method{List} + //! @relates List + //! + //! This is equivalent to `zip_with(into, xs, ys...)`, where `L` is + //! the data type of `xs`. + //! + //! @param xs, ys... + //! The lists to zip together. //! //! ### Example //! @snippet example/list/zip.cpp main @@ -410,33 +626,40 @@ namespace boost { namespace hana { >::zip_impl(xs, ys...); }; - /*! - Zip one list or more with a given function. - @method{List} - - Specifically, returns a list whose i-th element is `f(s1[i], ..., sn[i])`, - where `sk[i]` denotes the i-th element of the k-th list passed as an - argument. The returned list stops when the shortest input sequence is - exhausted. - - In other words, `zip_with(f, s1, ..., sn)` is a list of the form - @code - f(s1[0], ..., sn[0]) - f(s1[1], ..., sn[1]) - ... - f(s1[k], ..., sn[k]) - @endcode - where `k` is the length of the shortest list. - - ### Example - @snippet example/list/zip_with.cpp main - - @todo - - Consider allowing only two lists and achieving the variadic behavior - in some other way. This would make it possible to automatically curry - `zip_with`. It might be possible to achieve the variadic behavior with - e.g. Applicative Functors? - */ + //! Zip one list or more with a given function. + //! @relates List + //! + //! Specifically, returns a list whose i-th element is `f(s1[i], ..., sn[i])`, + //! where `sk[i]` denotes the i-th element of the k-th list passed as an + //! argument. The returned list stops when the shortest input sequence is + //! exhausted. + //! + //! In other words, `zip_with(f, s1, ..., sn)` is a list of the form + //! @code + //! f(s1[0], ..., sn[0]) + //! f(s1[1], ..., sn[1]) + //! ... + //! f(s1[k], ..., sn[k]) + //! @endcode + //! where `k` is the length of the shortest list. + //! + //! + //! @param f + //! A function called as `f(s1[k], ..., sn[k])`, where `si[k]` are + //! elements of the zipped lists as explained above. + //! + //! @param xs, ys... + //! The lists to zip with the given function. + //! + //! + //! ### Example + //! @snippet example/list/zip_with.cpp main + //! + //! @todo + //! Consider allowing only two lists and achieving the variadic behavior + //! in some other way. This would make it possible to automatically curry + //! `zip_with`. It might be possible to achieve the variadic behavior with + //! e.g. Applicative Functors? BOOST_HANA_CONSTEXPR_LAMBDA auto zip_with = [](auto f, auto xs, auto ...ys) { return List::instance< datatype_t diff --git a/include/boost/hana/list/mcd.hpp b/include/boost/hana/list/mcd.hpp index 4312704d1..88d8b1158 100644 --- a/include/boost/hana/list/mcd.hpp +++ b/include/boost/hana/list/mcd.hpp @@ -279,13 +279,14 @@ namespace boost { namespace hana { } }; - //! @details + //! `Applicative` instance for instances of the `List` type class. + //! //! A value can be lifted into a singleton list with `lift`. `ap(fs, xs)` //! applies each function in the list `fs` to each value in the list `xs`, //! and returns a list containing all the results. //! //! ### Example - //! @snippet example/list/applicative/overview.cpp main + //! @snippet example/list/applicative.cpp main template struct Applicative::instance()>> : Applicative::mcd @@ -299,13 +300,14 @@ namespace boost { namespace hana { { return bind(fs, [=](auto f) { return fmap(f, xs); }); } }; - //! @details + //! `Monad` instance for instances of the `List` type class. + //! //! A function returning a list of results can be mapped over all the //! elements of a list and have all the results concatenated using `bind`. //! Also, a list of lists can be flattened one level with `flatten`. //! //! ### Example - //! @snippet example/list/monad/overview.cpp main + //! @snippet example/list/monad.cpp main template struct Monad::instance()>> : Monad::flatten_mcd @@ -315,8 +317,7 @@ namespace boost { namespace hana { { return foldl(concat, nil, xss); } }; - //! @details - //! This instance is hard to describe in words; see the examples. + //! `Traversable` instance for `List` instances. //! //! ### Example //! @snippet example/list/traversable/traverse.cpp main