From 272ffa7900de07eef03b4e95393182ecbf9f67f5 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 17 Feb 2015 08:54:28 -0500 Subject: [PATCH] Add the MonadPlus concept --- example/list.cpp | 47 -- example/maybe.cpp | 18 + example/monad_plus.cpp | 110 ++++ include/boost/hana.hpp | 1 + include/boost/hana/ext/boost/fusion/deque.hpp | 26 +- include/boost/hana/ext/boost/fusion/list.hpp | 26 +- .../boost/hana/ext/boost/fusion/vector.hpp | 26 +- include/boost/hana/ext/boost/mpl/vector.hpp | 49 +- include/boost/hana/ext/boost/tuple.hpp | 27 +- include/boost/hana/ext/std/array.hpp | 90 ++- include/boost/hana/ext/std/tuple.hpp | 101 ++- .../boost/hana/fwd/ext/boost/mpl/vector.hpp | 4 +- include/boost/hana/fwd/list.hpp | 207 ------ include/boost/hana/fwd/maybe.hpp | 12 +- include/boost/hana/fwd/monad_plus.hpp | 549 ++++++++++++++++ include/boost/hana/list.hpp | 49 +- include/boost/hana/maybe.hpp | 21 + include/boost/hana/monad_plus.hpp | 217 ++++++ include/boost/hana/sandbox/lambda_tuple.hpp | 95 +-- include/boost/hana/tuple.hpp | 38 +- test/include/test/auto/list.hpp | 619 +++++++++++------- test/include/test/auto/monad_plus.hpp | 68 ++ test/include/test/seq.hpp | 35 +- test/maybe.cpp | 28 + test/sandbox/repeat.cpp | 27 +- test/sandbox/tuple_opts.cpp | 34 +- test/seq/main.hpp | 8 +- 27 files changed, 1789 insertions(+), 743 deletions(-) create mode 100644 example/monad_plus.cpp create mode 100644 include/boost/hana/fwd/monad_plus.hpp create mode 100644 include/boost/hana/monad_plus.hpp create mode 100644 test/include/test/auto/monad_plus.hpp diff --git a/example/list.cpp b/example/list.cpp index 377c5cd5d..80c167590 100644 --- a/example/list.cpp +++ b/example/list.cpp @@ -21,24 +21,6 @@ using namespace boost::hana; int main() { - { - //! [cons] - BOOST_HANA_CONSTEXPR_CHECK(cons(1, tuple()) == tuple(1)); - BOOST_HANA_CONSTEXPR_CHECK(cons(1, tuple('2', 3.3)) == tuple(1, '2', 3.3)); - BOOST_HANA_CONSTEXPR_CHECK(cons(1, cons('2', cons(3.3, tuple()))) == tuple(1, '2', 3.3)); - //! [cons] - } - - { - //! [filter] - BOOST_HANA_CONSTEXPR_CHECK( - filter(tuple(1, 2.0, 3, 4.0), trait_) - == - tuple(1, 3) - ); - //! [filter] - } - { //! [make] BOOST_HANA_CONSTANT_CHECK(make() == tuple()); @@ -83,15 +65,6 @@ int main() { //! [reverse] } - { - //! [concat] - using namespace literals; - BOOST_HANA_CONSTEXPR_CHECK( - concat(tuple(1, '2'), tuple(3.3, 4_c)) == tuple(1, '2', 3.3, 4_c) - ); - //! [concat] - } - { //! [group_by] BOOST_HANA_CONSTEXPR_CHECK( @@ -202,20 +175,6 @@ int main() { //! [take_c] } - { - //! [snoc] - BOOST_HANA_CONSTEXPR_CHECK(snoc(tuple(), 1) == tuple(1)); - BOOST_HANA_CONSTEXPR_CHECK(snoc(tuple(1, '2'), 3.3) == tuple(1, '2', 3.3)); - BOOST_HANA_CONSTEXPR_CHECK(snoc(snoc(snoc(tuple(), 1), '2'), 3.3) == tuple(1, '2', 3.3)); - //! [snoc] - } - - { - //! [repeat] - BOOST_HANA_CONSTEXPR_CHECK(repeat(int_<2>, 'x') == tuple('x', 'x')); - //! [repeat] - } - { //! [span] BOOST_HANA_CONSTEXPR_LAMBDA auto xs = tuple(int_<1>, int_<2>, int_<3>, int_<4>); @@ -259,12 +218,6 @@ int main() { //! [sort_by] } - { - //! [nil] - BOOST_HANA_CONSTANT_CHECK(nil() == tuple()); - //! [nil] - } - { //! [slice] BOOST_HANA_CONSTEXPR_CHECK( diff --git a/example/maybe.cpp b/example/maybe.cpp index 518d982c1..db625c7bf 100644 --- a/example/maybe.cpp +++ b/example/maybe.cpp @@ -64,6 +64,24 @@ BOOST_HANA_CONSTEXPR_CHECK(flatten(just(just(2))) == just(2)); }{ +//! [monad_plus] +BOOST_HANA_CONSTEXPR_CHECK( + concat(nothing, just('x')) == just('x') +); + +BOOST_HANA_CONSTANT_CHECK( + concat(nothing, nothing) == nothing +); + +BOOST_HANA_CONSTEXPR_CHECK( + concat(just('x'), just('y')) == just('x') +); + +BOOST_HANA_CONSTANT_CHECK(nil() == nothing); +//! [monad_plus] + +}{ + //! [traversable] BOOST_HANA_CONSTEXPR_LAMBDA auto replicate3 = [](auto x) { return tuple(x, x, x); diff --git a/example/monad_plus.cpp b/example/monad_plus.cpp new file mode 100644 index 000000000..0c8d1cdcd --- /dev/null +++ b/example/monad_plus.cpp @@ -0,0 +1,110 @@ +/* +@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 +using namespace boost::hana; + + +int main() { + +{ + +//! [concat] +using namespace literals; +BOOST_HANA_CONSTEXPR_CHECK( + concat(tuple(1, '2'), tuple(3.3, 4_c)) == tuple(1, '2', 3.3, 4_c) +); +//! [concat] + +}{ + +//! [nil] +BOOST_HANA_CONSTANT_CHECK(nil() == tuple()); +BOOST_HANA_CONSTANT_CHECK(nil() == nothing); +//! [nil] + +}{ + +//! [prepend] +BOOST_HANA_CONSTEXPR_CHECK(prepend(1, tuple()) == tuple(1)); +BOOST_HANA_CONSTEXPR_CHECK(prepend(1, tuple('2', 3.3)) == tuple(1, '2', 3.3)); +BOOST_HANA_CONSTEXPR_CHECK( + prepend(1, prepend('2', prepend(3.3, tuple()))) == tuple(1, '2', 3.3) +); +//! [prepend] + +}{ + +//! [append] +BOOST_HANA_CONSTEXPR_CHECK(append(tuple(), 1) == tuple(1)); +BOOST_HANA_CONSTEXPR_CHECK(append(tuple(1, '2'), 3.3) == tuple(1, '2', 3.3)); +BOOST_HANA_CONSTEXPR_CHECK( + append(append(append(tuple(), 1), '2'), 3.3) == tuple(1, '2', 3.3) +); +//! [append] + +}{ + +//! [filter] +BOOST_HANA_CONSTEXPR_CHECK( + filter(tuple(1, 2.0, 3, 4.0), trait_) == tuple(1, 3) +); + +BOOST_HANA_CONSTEXPR_CHECK( + filter(just(3), trait_) == just(3) +); + +BOOST_HANA_CONSTANT_CHECK( + filter(just(3.0), trait_) == nothing +); +//! [filter] + +}{ + +//! [cycle] +BOOST_HANA_CONSTEXPR_CHECK( + cycle(size_t<2>, tuple('x', 'y', 'z')) == tuple('x', 'y', 'z', 'x', 'y', 'z') +); +//! [cycle] + +}{ + +//! [repeat] +BOOST_HANA_CONSTEXPR_CHECK(repeat(size_t<2>, 'x') == tuple('x', 'x')); + +// Of course, because Maybe can hold at most one element. +static_assert(repeat(size_t<2>, 'x') == just('x'), ""); +//! [repeat] + +}{ + +//! [prefix] +using namespace std::literals; +BOOST_HANA_RUNTIME_CHECK( + prefix("my"s, tuple("dog"s, "car"s, "house"s)) == + tuple("my", "dog", "my", "car", "my", "house") +); +//! [prefix] + +}{ + +//! [suffix] +BOOST_HANA_CONSTEXPR_CHECK( + suffix(0, tuple(1, 2, 3, 4)) == tuple(1, 0, 2, 0, 3, 0, 4, 0) +); +//! [suffix] + +} + +} diff --git a/include/boost/hana.hpp b/include/boost/hana.hpp index 0dd34b098..fc2752b2d 100644 --- a/include/boost/hana.hpp +++ b/include/boost/hana.hpp @@ -42,6 +42,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include diff --git a/include/boost/hana/ext/boost/fusion/deque.hpp b/include/boost/hana/ext/boost/fusion/deque.hpp index fc8ced215..449a6a845 100644 --- a/include/boost/hana/ext/boost/fusion/deque.hpp +++ b/include/boost/hana/ext/boost/fusion/deque.hpp @@ -17,6 +17,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include @@ -45,21 +46,34 @@ namespace boost { namespace hana { }; ////////////////////////////////////////////////////////////////////////// - // List + // MonadPlus ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance - : List::mcd - { + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + + template <> + struct prepend_impl { template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { + static constexpr decltype(auto) apply(X&& x, Xs&& xs) { return ::boost::fusion::as_deque( ::boost::fusion::push_front( detail::std::forward(xs), detail::std::forward(x))); } + }; - static auto nil_impl() + template <> + struct nil_impl { + static auto apply() { return ::boost::fusion::deque<>{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/boost/fusion/list.hpp b/include/boost/hana/ext/boost/fusion/list.hpp index 305552bc9..af58ea4d8 100644 --- a/include/boost/hana/ext/boost/fusion/list.hpp +++ b/include/boost/hana/ext/boost/fusion/list.hpp @@ -17,6 +17,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include @@ -45,21 +46,34 @@ namespace boost { namespace hana { }; ////////////////////////////////////////////////////////////////////////// - // List + // MonadPlus ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance - : List::mcd - { + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + + template <> + struct prepend_impl { template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { + static constexpr decltype(auto) apply(X&& x, Xs&& xs) { return ::boost::fusion::as_list( ::boost::fusion::push_front( detail::std::forward(xs), detail::std::forward(x))); } + }; - static auto nil_impl() + template <> + struct nil_impl { + static auto apply() { return ::boost::fusion::list<>{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/boost/fusion/vector.hpp b/include/boost/hana/ext/boost/fusion/vector.hpp index 32ec940cc..fb63b8cc5 100644 --- a/include/boost/hana/ext/boost/fusion/vector.hpp +++ b/include/boost/hana/ext/boost/fusion/vector.hpp @@ -17,6 +17,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include @@ -45,21 +46,34 @@ namespace boost { namespace hana { }; ////////////////////////////////////////////////////////////////////////// - // List + // MonadPlus ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance - : List::mcd - { + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + + template <> + struct prepend_impl { template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { + static constexpr decltype(auto) apply(X&& x, Xs&& xs) { return ::boost::fusion::as_vector( ::boost::fusion::push_front( detail::std::forward(xs), detail::std::forward(x))); } + }; - static auto nil_impl() + template <> + struct nil_impl { + static auto apply() { return ::boost::fusion::vector<>{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/boost/mpl/vector.hpp b/include/boost/hana/ext/boost/mpl/vector.hpp index e72453af4..73a5ca512 100644 --- a/include/boost/hana/ext/boost/mpl/vector.hpp +++ b/include/boost/hana/ext/boost/mpl/vector.hpp @@ -15,13 +15,12 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include -#include - -// instances #include #include #include +#include #include +#include #include #include @@ -60,11 +59,6 @@ namespace boost { namespace hana { ////////////////////////////////////////////////////////////////////////// // Iterable ////////////////////////////////////////////////////////////////////////// - - //! `Iterable` instance for Boost.MPL vectors. - //! - //! ### Example - //! @include example/ext/boost/mpl/vector/iterable.cpp template <> struct head_impl { template @@ -86,28 +80,37 @@ namespace boost { namespace hana { { return typename ::boost::mpl::empty::type{}; } }; - //! `List` instance for Boost.MPL vectors. - //! - //! Note that since Boost.MPL vectors can only hold types, - //! only `Type`s can be used with `cons`. - //! - //! ### Example - //! @include example/ext/boost/mpl/vector/list.cpp + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance - : List::mcd - { - template - static constexpr auto cons_impl(x, xs) { - static_assert(detail::std::is_same, Type>::value, + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + + template <> + struct prepend_impl { + template + static constexpr auto apply(X, Xs) { + static_assert(detail::std::is_same, Type>::value, "Only Types may be prepended to a Boost.MPL vector."); return typename ::boost::mpl::push_front< - xs, typename x::type + Xs, typename X::type >::type{}; } + }; - static constexpr auto nil_impl() + template <> + struct nil_impl { + static constexpr auto apply() { return ::boost::mpl::vector0<>{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/boost/tuple.hpp b/include/boost/hana/ext/boost/tuple.hpp index 9052c18a3..cfe0b598d 100644 --- a/include/boost/hana/ext/boost/tuple.hpp +++ b/include/boost/hana/ext/boost/tuple.hpp @@ -15,11 +15,10 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include - -// instances #include #include #include +#include #include #include @@ -79,17 +78,35 @@ namespace boost { namespace hana { { return false_; } }; + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance : List::mcd { + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + + template <> + struct prepend_impl { template - static constexpr auto cons_impl(X x, Xs xs) { + static constexpr auto apply(X x, Xs xs) { return ::boost::tuples::cons{ detail::std::move(x), detail::std::move(xs) }; } + }; - static constexpr auto nil_impl() + template <> + struct nil_impl { + static constexpr auto apply() { return ::boost::tuples::null_type{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/std/array.hpp b/include/boost/hana/ext/std/array.hpp index d6491f315..8a11590c2 100644 --- a/include/boost/hana/ext/std/array.hpp +++ b/include/boost/hana/ext/std/array.hpp @@ -12,17 +12,20 @@ Distributed under the Boost Software License, Version 1.0. #include +#include #include +#include +#include +#include #include #include #include #include #include - -// instances #include #include #include +#include #include #include @@ -93,37 +96,76 @@ namespace boost { namespace hana { { return bool_; } }; + ////////////////////////////////////////////////////////////////////////// + // Applicative + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance : List::mcd { - struct anything { }; + struct lift_impl { + template + static constexpr decltype(auto) apply(X&& x) { + using T = typename detail::std::decay::type; + return ::std::array{{detail::std::forward(x)}}; + } + }; - static constexpr auto nil_impl() - { return ::std::array{}; } - - template - static constexpr auto - cons_helper(X&& x, Xs&& xs, detail::std::index_sequence) { - return ::std::array{{ - detail::std::forward(x), - detail::std::forward(xs)[index]... + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// + template <> + struct concat_impl { + template + static constexpr auto concat_helper(Xs&& xs, Ys&& ys, + detail::std::index_sequence, + detail::std::index_sequence) + { + return ::std::array{{ + detail::std::forward(xs)[i]..., + detail::std::forward(ys)[j]... }}; } - template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { - using RawArray = typename detail::std::remove_reference::type; - constexpr auto N = ::std::tuple_size::value; - using T = typename RawArray::value_type; - return cons_helper( - detail::std::forward(x), + template ::type, + typename RawYs = typename detail::std::remove_reference::type, + detail::std::size_t xs_len = ::std::tuple_size::value, + detail::std::size_t ys_len = ::std::tuple_size::value, + typename = detail::std::enable_if_t + > + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + using T = typename detail::std::common_type< + typename RawXs::value_type, + typename RawYs::value_type + >::type; + + return concat_helper( detail::std::forward(xs), - detail::std::make_index_sequence{} + detail::std::forward(ys), + detail::std::make_index_sequence{}, + detail::std::make_index_sequence{} ); } - template - static constexpr auto cons_impl(X x, ::std::array) - { return ::std::array{{detail::std::move(x)}}; } + template + static constexpr Ys apply(::std::array, Ys&& ys) + { return detail::std::forward(ys); } + + template + static constexpr auto apply(::std::array, ::std::array) { + using C = typename detail::std::common_type::type; + return ::std::array{}; + } + + template + static constexpr Xs apply(Xs&& xs, ::std::array) + { return detail::std::forward(xs); } + }; + + template <> + struct nil_impl { + struct anything { }; + static constexpr auto apply() + { return ::std::array{}; } }; }} // end namespace boost::hana diff --git a/include/boost/hana/ext/std/tuple.hpp b/include/boost/hana/ext/std/tuple.hpp index 6a3c86812..7a829fe4d 100644 --- a/include/boost/hana/ext/std/tuple.hpp +++ b/include/boost/hana/ext/std/tuple.hpp @@ -12,24 +12,36 @@ Distributed under the Boost Software License, Version 1.0. #include +#include #include +#include #include #include #include #include - -// instances #include #include #include #include #include +#include #include #include namespace boost { namespace hana { + ////////////////////////////////////////////////////////////////////////// + // make + ////////////////////////////////////////////////////////////////////////// + template <> + struct make_impl { + template + static constexpr decltype(auto) apply(Xs&& ...xs) { + return ::std::make_tuple(detail::std::forward(xs)...); + } + }; + ////////////////////////////////////////////////////////////////////////// // Functor ////////////////////////////////////////////////////////////////////////// @@ -55,6 +67,57 @@ namespace boost { namespace hana { } }; + ////////////////////////////////////////////////////////////////////////// + // Applicative + ////////////////////////////////////////////////////////////////////////// + template <> + struct lift_impl { + template + static constexpr auto apply(X&& x) { + return ::std::tuple::type>{ + detail::std::forward(x)}; + } + }; + + ////////////////////////////////////////////////////////////////////////// + // Monad + ////////////////////////////////////////////////////////////////////////// + template <> + struct flatten_impl { + template + static constexpr decltype(auto) + flatten_helper(Xs&& xs, detail::std::index_sequence) { + return ::std::tuple_cat( + ::std::get(detail::std::forward(xs))...); + } + + template + static constexpr decltype(auto) apply(Xs&& xs) { + using Raw = typename detail::std::remove_reference::type; + constexpr detail::std::size_t len = ::std::tuple_size::value; + return flatten_helper(detail::std::forward(xs), + detail::std::make_index_sequence{}); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// + template <> + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return ::std::tuple_cat(detail::std::forward(xs), + detail::std::forward(ys)); + } + }; + + template <> + struct nil_impl { + static constexpr auto apply() + { return ::std::tuple<>{}; } + }; + ////////////////////////////////////////////////////////////////////////// // Foldable ////////////////////////////////////////////////////////////////////////// @@ -128,40 +191,6 @@ namespace boost { namespace hana { return ::std::get(detail::std::forward(xs)); } }; - - template <> - struct List::instance : List::mcd { - static constexpr auto nil_impl() - { return ::std::tuple<>{}; } - - template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { - return ::std::tuple_cat( - ::std::make_tuple(detail::std::forward(x)), - detail::std::forward(xs) - ); - } - - template - static constexpr decltype(auto) make_impl(Xs&& ...xs) { - return ::std::make_tuple(detail::std::forward(xs)...); - } - }; - - ////////////////////////////////////////////////////////////////////////// - // Monad - ////////////////////////////////////////////////////////////////////////// - template <> - struct flatten_impl { - template - static constexpr auto helper(::std::tuple tuples, - detail::std::index_sequence) - { return ::std::tuple_cat(::std::get(tuples)...); } - - template - static constexpr decltype(auto) apply(::std::tuple tuples) - { return helper(tuples, detail::std::index_sequence_for{}); } - }; }} // end namespace boost::hana #endif // !BOOST_HANA_EXT_STD_TUPLE_HPP diff --git a/include/boost/hana/fwd/ext/boost/mpl/vector.hpp b/include/boost/hana/fwd/ext/boost/mpl/vector.hpp index 8158e4bb9..23638b96e 100644 --- a/include/boost/hana/fwd/ext/boost/mpl/vector.hpp +++ b/include/boost/hana/fwd/ext/boost/mpl/vector.hpp @@ -29,7 +29,9 @@ namespace boost { namespace hana { //! @endcode //! //! ## Instance of - //! `Functor`, `Iterable`, `List` and `Comparable` + //! `Functor`, `Iterable`, `List` and `Comparable`\n + //! Note that since Boost.MPL vectors can only hold types, + //! only `Type`s can be used with `cons`. //! //! ## MPL / Hana cheat sheet //! This section presents correspondences between operations with the diff --git a/include/boost/hana/fwd/list.hpp b/include/boost/hana/fwd/list.hpp index b9f2b038e..c99f2193b 100644 --- a/include/boost/hana/fwd/list.hpp +++ b/include/boost/hana/fwd/list.hpp @@ -57,111 +57,6 @@ namespace boost { namespace hana { struct mcd; }; - //! Concatenate two lists together. - //! @relates List - //! - //! @param xs, ys - //! Two instances of `List` with _the same data type_. - //! - //! ### Example - //! @snippet example/list.cpp concat -#ifdef BOOST_HANA_DOXYGEN_INVOKED - constexpr auto concat = [](auto&& xs, auto&& ys) -> decltype(auto) { - return tag-dispatched; - }; -#else - struct _concat { - template - constexpr decltype(auto) operator()(Xs&& xs, Ys&& ys) const { - static_assert(detail::std::is_same< - datatype_t, datatype_t - >::value, - "boost::hana::concat: both arguments must have the same data type"); - return List::instance< - datatype_t - >::concat_impl( - detail::std::forward(xs), - detail::std::forward(ys) - ); - } - }; - - constexpr _concat concat{}; -#endif - - //! Prepend an element to the head of a 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.cpp cons -#ifdef BOOST_HANA_DOXYGEN_INVOKED - constexpr auto cons = [](auto&& x, auto&& xs) -> decltype(auto) { - return tag-dispatched; - }; -#else - struct _cons { - template - constexpr decltype(auto) operator()(X&& x, Xs&& xs) const { - return List::instance< - datatype_t - >::cons_impl( - detail::std::forward(x), - detail::std::forward(xs) - ); - } - }; - - constexpr _cons cons{}; -#endif - - //! Return a list containing only the elements satisfying a `predicate`. - //! @relates List - //! - //! - //! @param xs - //! The list to filter. - //! - //! @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`. - //! - //! - //! ### Example - //! @snippet example/list.cpp filter - //! - //! ### Benchmarks - //! @image html benchmark/list/filter.ctime.png -#ifdef BOOST_HANA_DOXYGEN_INVOKED - constexpr auto filter = [](auto&& xs, auto&& predicate) -> decltype(auto) { - return tag-dispatched; - }; -#else - struct _filter { - template - constexpr decltype(auto) operator()(Xs&& xs, Pred&& pred) const { - return List::instance< - datatype_t - >::filter_impl( - detail::std::forward(xs), - detail::std::forward(pred) - ); - } - }; - - constexpr _filter filter{}; -#endif - //! Group the elements of a list into subgroups of adjacent elements that //! are "equal" with respect to a predicate. //! @relates List @@ -337,33 +232,6 @@ namespace boost { namespace hana { }; #endif - //! `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.cpp nil -#ifdef BOOST_HANA_DOXYGEN_INVOKED - template - constexpr auto nil = []() -> decltype(auto) { - return tag-dispatched; - }; -#else - template - struct _nil { - constexpr decltype(auto) operator()() const { - return List::instance::nil_impl(); - } - }; - - template - constexpr _nil nil{}; -#endif - //! Partition a list based on a `predicate`. //! @relates List //! @@ -504,48 +372,6 @@ namespace boost { namespace hana { constexpr _remove_at_c remove_at_c{}; #endif - //! Create a list containing `n` copies of a value. - //! @relates List - //! - //! Specifically, `repeat(n, x)` is a list of data type `L` containing - //! `n` copies of `x`. - //! - //! - //! @tparam L - //! The data type of the list to create. It must be an instance of `List`. - //! - //! @param n - //! An `IntegralConstant` representing the number of copies of `x` to - //! shove into the returned list. - //! - //! @param x - //! The value to fill the list with. - //! - //! - //! ### Example - //! @snippet example/list.cpp repeat -#ifdef BOOST_HANA_DOXYGEN_INVOKED - template - constexpr auto repeat = [](auto&& n, auto&& x) -> decltype(auto) { - return tag-dispatched; - }; -#else - template - struct _repeat { - template - constexpr decltype(auto) operator()(N&& n, X&& x) const { - return List::instance::repeat_impl( - detail::std::forward(n), - detail::std::forward(x) - ); - } - }; - - template - constexpr _repeat repeat{}; -#endif - - //! Reverse a list. //! @relates List //! @@ -807,39 +633,6 @@ namespace boost { namespace hana { constexpr _slice_c slice_c{}; #endif - //! Append an element to the end of a 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.cpp snoc -#ifdef BOOST_HANA_DOXYGEN_INVOKED - constexpr auto snoc = [](auto&& xs, auto&& x) -> decltype(auto) { - return tag-dispatched; - }; -#else - struct _snoc { - template - constexpr decltype(auto) operator()(Xs&& xs, X&& x) const { - return List::instance< - datatype_t - >::snoc_impl( - detail::std::forward(xs), - detail::std::forward(x) - ); - } - }; - - constexpr _snoc snoc{}; -#endif - //! Sort a list based on the `less` [strict weak ordering](@ref strict_weak_ordering). //! @relates List //! diff --git a/include/boost/hana/fwd/maybe.hpp b/include/boost/hana/fwd/maybe.hpp index f112c9096..f1c96235b 100644 --- a/include/boost/hana/fwd/maybe.hpp +++ b/include/boost/hana/fwd/maybe.hpp @@ -88,20 +88,26 @@ namespace boost { namespace hana { //! Example: //! @snippet example/maybe.cpp monad //! - //! 6. `Traversable`\n + //! 6. `MonadPlus`\n + //! The `Maybe` MonadPlus makes it easy to choose the first valid value + //! of two optional values. If both optional values are `nothing`s, then + //! `concat` will return `nothing`. + //! @snippet example/maybe.cpp monad_plus + //! + //! 7. `Traversable`\n //! Traversing `nothing` yields `nothing` in the new applicative, and //! traversing `just(x)` applies the function and maps `just` inside //! the resulting applicative. //! Example: //! @snippet example/maybe.cpp traversable //! - //! 7. `Foldable`\n + //! 8. `Foldable`\n //! Folding a `Maybe` is equivalent to folding a `List` containing either //! no elements (for `nothing`) or `x` (for `just(x)`). //! Example: //! @snippet example/maybe.cpp foldable //! - //! 8. `Searchable`\n + //! 9. `Searchable`\n //! Searching a `Maybe` is equivalent to searching a list containing //! `x` for `just(x)` and an empty list for `nothing`. //! Example: diff --git a/include/boost/hana/fwd/monad_plus.hpp b/include/boost/hana/fwd/monad_plus.hpp new file mode 100644 index 000000000..a57598ba1 --- /dev/null +++ b/include/boost/hana/fwd/monad_plus.hpp @@ -0,0 +1,549 @@ +/*! +@file +Forward declares `boost::hana::MonadPlus`. + +@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_FWD_MONAD_PLUS_HPP +#define BOOST_HANA_FWD_MONAD_PLUS_HPP + +#include +#include +#include + + +namespace boost { namespace hana { + //! @ingroup group-concepts + //! The `MonadPlus` concept represents Monads with a monoidal structure. + //! + //! Intuitively, whereas a Monad can be seen as some kind of container + //! or context, a MonadPlus can be seen as a container or a context that + //! can be concatenated with other containers or contexts. There must + //! also be an identity element for this combining operation. For example, + //! a `Tuple` is a MonadPlus, because tuples can be concatenated and the + //! empty tuple would act as an identity for concatenation. How is this + //! different from a Monad which is also a Monoid? The answer is that the + //! monoidal structure on a MonadPlus must _not_ depend of the contents + //! of the structure; it must not require the contents to be a Monoid + //! in order to work. + //! + //! While sequences are not the only possible model for MonadPlus, the + //! method names used here refer to the MonadPlus of sequences under + //! concatenation. Several useful functions generalizing operations on + //! sequences are included with this concept, like `append`, `prepend` + //! and `filter`. + //! + //! + //! Superclasses + //! ------------ + //! `Functor`, `Applicative` and `Monad` + //! + //! + //! Minimal complete definition + //! --------------------------- + //! `concat` and `nil` + //! + //! + //! Laws + //! ---- + //! First, a MonadPlus is required to have a monoidal structure. Hence, it + //! is no surprise that we require a MonadPlus `M` to be a monoid. For + //! all objects `a, b, c` of a MonadPlus `M`, + //! @code + //! // identity + //! concat(nil(), a) == a + //! concat(a, nil()) == a + //! + //! // associativity + //! concat(a, concat(b, c)) == concat(concat(a, b), c) + //! @endcode + //! + //! Second, a MonadPlus is also required to obey the following laws, + //! which represent the fact that `nil()` must be some kind of + //! absorbing element for the `bind` operation. + //! @code + //! bind(nil(), f) == nil() + //! bind(a, always(nil())) == nil() + //! @endcode + struct MonadPlus { }; + + //! Combine two monadic structures together. + //! @relates MonadPlus + //! + //! Given two monadic structures, `concat` combines them together and + //! returns a new monadic structure. The exact definition of `concat` + //! will depend on the exact model of MonadPlus at hand, but for + //! sequences it corresponds intuitively to simple concatenation. + //! + //! Also note that combination is not required to be commutative. In other + //! words, there is no requirement that + //! @code + //! concat(xs, ys) == concat(ys, xs) + //! @endcode + //! , and it does not hold in general. + //! + //! + //! @param xs, ys + //! Two monadic structures to combine together. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp concat +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto concat = [](auto&& xs, auto&& ys) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct concat_impl; + + struct _concat { + template + constexpr decltype(auto) operator()(Xs&& xs, Ys&& ys) const { + static_assert(detail::std::is_same< + typename datatype::type, typename datatype::type + >{}, + "boost::hana::concat: both arguments must have the same data type"); + return concat_impl::type>::apply( + detail::std::forward(xs), + detail::std::forward(ys) + ); + } + }; + + constexpr _concat concat{}; +#endif + + //! Identity of the monadic combination `concat`. + //! @relates MonadPlus + //! + //! + //! @tparam M + //! The data type of the monadic structure to return. This must be + //! a model of the MonadPlus concept. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp nil +#ifdef BOOST_HANA_DOXYGEN_INVOKED + template + constexpr auto nil = []() -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct nil_impl; + + template + struct _nil { + constexpr decltype(auto) operator()() const { + return nil_impl::apply(); + } + }; + + template + constexpr _nil nil{}; +#endif + + //! Prepend an element to a monadic structure. + //! @relates MonadPlus + //! + //! Given an element `x` of data type `X` and a monadic structure + //! `xs` containing objects of data type `X`, `prepend` returns a + //! new monadic structure which is the result of lifting `x` into + //! the monadic structure and then combining that (to the left) + //! with `xs`. In other words, + //! @code + //! prepend(x, xs) == concat(lift(x), xs) + //! @endcode + //! + //! For sequences, this has the intuitive behavior of simply prepending + //! an element to the beginning of the sequence, hence the name. + //! + //! > #### Rationale for not calling this `push_front` + //! > While `push_front` is the de-facto name used in the standard library, + //! > it also strongly suggests mutation of the underlying sequence, which + //! > is not the case here. The author also finds that `push_front` + //! > suggests too strongly the sole interpretation of putting an + //! > element to the front of a sequence, whereas `prepend` is slightly + //! > more nuanced and bears its name better for e.g. `Maybe`. + //! + //! + //! @param x + //! An element to combine to the left of the monadic structure. + //! + //! @param xs + //! A monadic structure that will be combined to the right of the element. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp prepend +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto prepend = [](auto&& x, auto&& xs) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct prepend_impl; + + struct _prepend { + template + constexpr decltype(auto) operator()(X&& x, Xs&& xs) const { + return prepend_impl::type>::apply( + detail::std::forward(x), + detail::std::forward(xs) + ); + } + }; + + constexpr _prepend prepend{}; + constexpr auto cons = prepend; //! @todo Remove this; for bw compat. +#endif + + //! Append an element to a monadic structure. + //! @relates MonadPlus + //! + //! Given an element `x` of data type `X` and a monadic structure + //! `xs` containing objects of data type `X`, `append` returns a + //! new monadic structure which is the result of lifting `x` into + //! the monadic structure and then combining that (to the right) + //! with `xs`. In other words, + //! @code + //! append(xs, x) == concat(xs, lift(x)) + //! @endcode + //! + //! For sequences, this has the intuitive behavior of simply appending + //! an element to the end of the sequence, hence the name. + //! + //! > #### Rationale for not calling this `push_back` + //! > See the rationale for using `prepend` instead of `push_front`. + //! + //! + //! @param xs + //! A monadic structure that will be combined to the left of the element. + //! + //! @param x + //! An element to combine to the right of the monadic structure. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp append +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto append = [](auto&& xs, auto&& x) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct append_impl; + + struct _append { + template + constexpr decltype(auto) operator()(Xs&& xs, X&& x) const { + return append_impl::type>::apply( + detail::std::forward(xs), + detail::std::forward(x) + ); + } + }; + + constexpr _append append{}; + constexpr auto snoc = append; //! @todo Remove this; for bw compat. +#endif + + //! Filter a monadic structure using a custom predicate. + //! @relates MonadPlus + //! + //! Given a monadic structure and a predicate, `filter` returns a new + //! monadic structure containing only those elements that satisfy the + //! predicate. This is a generalization of the usual `filter` function + //! for sequences; it works for any MonadPlus. Intuitively, `filter` is + //! somewhat equivalent to: + //! @code + //! filter(xs, pred) == flatten(transform(xs, [](auto x) { + //! return pred(x) ? lift(x) : nil(); + //! }) + //! @endcode + //! In other words, we basically turn a monadic structure containing + //! `[x1, ..., xn]` into a monadic structure containing + //! @code + //! [ + //! pred(x1) ? [x1] : [], + //! pred(x2) ? [x2] : [], + //! ... + //! pred(xn) ? [xn] : [] + //! ] + //! @endcode + //! , and we then `flatten` that. + //! + //! + //! @param xs + //! The monadic structure to filter. + //! + //! @param pred + //! A function called as `pred(x)` for each element `x` in the monadic + //! structure and returning a `Logical` representing whether that element + //! should be __kept__ in the resulting structure. In the current version + //! of the library, the predicate has to return a compile-time `Logical`. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp filter + //! + //! + //! Benchmarks + //! ---------- + //! @image html benchmark/monad_plus/filter.ctime.png +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto filter = [](auto&& xs, auto&& pred) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct filter_impl; + + struct _filter { + template + constexpr decltype(auto) operator()(Xs&& xs, Pred&& pred) const { + return filter_impl::type>::apply( + detail::std::forward(xs), + detail::std::forward(pred) + ); + } + }; + + constexpr _filter filter{}; +#endif + + //! Combine a monadic structure with itself `n` times. + //! @relates MonadPlus + //! + //! Given a non-negative number `n` and a monadic structure `xs`, + //! `cycle` returns a new monadic structure which is the result of + //! combining `xs` with itself `n` times using the `concat` operation. + //! In other words, + //! @code + //! cycle(n, xs) == concat(xs, concat(xs, ... concat(xs, xs))) + //! // ^^^^^ n times total + //! @endcode + //! + //! Also note that since `concat` is required to be associative, we + //! could also have written + //! @code + //! cycle(n, xs) == concat(concat(... concat(xs, xs), xs), xs) + //! // ^^^^^ n times total + //! @endcode + //! + //! If `n` is zero, then the identity of `concat`, `nil`, is returned. + //! In the case of sequences, this boils down to returning a sequence + //! which containes `n` copies of itself; for other models it might + //! differ. + //! + //! + //! @param n + //! A non-negative `Constant` of an unsigned integral type representing + //! the number of times to combine the monadic structure with itself. + //! If `n` is zero, `cycle` returns `nil`. + //! + //! @param xs + //! A monadic structure to combine with itself a certain number of times. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp cycle +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto cycle = [](auto&& n, auto&& xs) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct cycle_impl; + + struct _cycle { + template + constexpr decltype(auto) operator()(N&& n, Xs&& xs) const { + return cycle_impl::type>::apply( + detail::std::forward(n), + detail::std::forward(xs) + ); + } + }; + + constexpr _cycle cycle{}; +#endif + + //! Create a monadic structure by combining a lifted value with itself + //! `n` times. + //! @relates MonadPlus + //! + //! Given a non-negative number `n`, a value `x` and a monadic data type + //! `M`, `repeat` creates a new monadic structure which is the result of + //! combining `x` with itself `n` times inside the monadic structure. + //! In other words, `repeat` simply `lift`s `x` into the monadic structure, + //! and then combines that with itself `n` times: + //! @code + //! repeat(n, x) == cycle(n, lift(x)) + //! @endcode + //! + //! If `n` is zero, then the identity of the `concat` operation is returned. + //! In the case of sequences, this corresponds to creating a new sequence + //! holding `n` copies of `x`. + //! + //! + //! @tparam M + //! The data type of the returned monadic structure. It must be a model of + //! the MonadPlus concept. + //! + //! @param n + //! A non-negative `Constant` of an unsigned integral type representing + //! the number of times to combine `lift(x)` with itself. If `n == 0`, + //! then `repeat` returns `nil()`. + //! + //! @param x + //! The value to lift into a monadic structure and then combine with + //! itself. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp repeat +#ifdef BOOST_HANA_DOXYGEN_INVOKED + template + constexpr auto repeat = [](auto&& n, auto&& x) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct repeat_impl; + + template + struct _repeat { + template + constexpr decltype(auto) operator()(N&& n, X&& x) const { + return repeat_impl::apply( + detail::std::forward(n), + detail::std::forward(x) + ); + } + }; + + template + constexpr _repeat repeat{}; +#endif + + //! Inserts a value before each element of a monadic structure. + //! @relates MonadPlus + //! + //! Given a value (called the prefix) `z` and a monadic structure `xs`, + //! `prefix` returns a new monadic structure which is equivalent to + //! @code + //! prefix(z, xs) == flatten(transform(xs, [](auto x) { + //! return concat(lift(z), lift(x)); + //! })) + //! @endcode + //! + //! For sequences, this simply corresponds to inserting the prefix before + //! each element of the sequence. For example, given a sequence + //! `[x1, ..., xn]`, `prefix` will return + //! @code + //! [z, x1, z, x2, ..., z, xn] + //! @endcode + //! As explained above, this can be generalized to other MonadPlus models, + //! with various levels of interest. + //! + //! + //! @param z + //! A value (the prefix) to insert before each element of a monadic + //! structure. + //! + //! @param xs + //! A monadic structure. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp prefix +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto prefix = [](auto&& z, auto&& xs) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct prefix_impl; + + struct _prefix { + template + constexpr decltype(auto) operator()(Z&& z, Xs&& xs) const { + return prefix_impl::type>::apply( + detail::std::forward(z), + detail::std::forward(xs) + ); + } + }; + + constexpr _prefix prefix{}; +#endif + + //! Inserts a value after each element of a monadic structure. + //! @relates MonadPlus + //! + //! Given a value (called the suffix) `z` and a monadic structure `xs`, + //! `suffix` returns a new monadic structure which is equivalent to + //! @code + //! suffix(z, xs) == flatten(transform(xs, [](auto x) { + //! return concat(lift(x), lift(z)); + //! })) + //! @endcode + //! + //! For sequences, this simply corresponds to inserting the suffix after + //! each element of the sequence. For example, given a sequence + //! `[x1, ..., xn]`, `suffix` will return + //! @code + //! [x1, z, x2, z, ..., xn, z] + //! @endcode + //! As explained above, this can be generalized to other MonadPlus models, + //! with various levels of interest. + //! + //! + //! @param z + //! A value (the suffix) to insert after each element of a monadic + //! structure. + //! + //! @param xs + //! A monadic structure. + //! + //! + //! Example + //! ------- + //! @snippet example/monad_plus.cpp suffix +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto suffix = [](auto&& z, auto&& xs) -> decltype(auto) { + return tag-dispatched; + }; +#else + template + struct suffix_impl; + + struct _suffix { + template + constexpr decltype(auto) operator()(Z&& z, Xs&& xs) const { + return suffix_impl::type>::apply( + detail::std::forward(z), + detail::std::forward(xs) + ); + } + }; + + constexpr _suffix suffix{}; +#endif +}} // end namespace boost::hana + +#endif // !BOOST_HANA_FWD_MONAD_PLUS_HPP diff --git a/include/boost/hana/list.hpp b/include/boost/hana/list.hpp index acb60eac8..7f0923244 100644 --- a/include/boost/hana/list.hpp +++ b/include/boost/hana/list.hpp @@ -35,6 +35,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include @@ -48,30 +49,15 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { + template + struct List::instance{}>> + : List::mcd + { }; + //! Minimal complete definition: - //! `Monad`, `Iterable`, `Foldable`, `cons`, and `nil` + //! `Monad`, `Iterable`, `Foldable`, `MonadPlus` template struct List::mcd { - template - static constexpr decltype(auto) concat_impl(Xs&& xs, Ys&& ys) { - return foldr( - detail::std::forward(xs), - detail::std::forward(ys), - cons - ); - } - - template - static constexpr auto filter_impl(Xs xs, Pred pred) { - auto go = [=](auto x, auto xs) { - return eval_if(pred(x), - [=](auto _) { return _(cons)(x, xs); }, - always(xs) - ); - }; - return foldr(xs, nil(), go); - } - template static constexpr auto group_by_impl(Pred pred, Xs xs_) { return eval_if(is_empty(xs_), @@ -199,18 +185,6 @@ namespace boost { namespace hana { ); } - template - static constexpr decltype(auto) - repeat_helper(X&& x, detail::std::integer_sequence) { - return make(((void)i, x)...); - } - - template - static constexpr auto repeat_impl(N n, X x) { - constexpr auto m = value(n); - return repeat_helper(x, detail::std::make_integer_sequence{}); - } - template static constexpr decltype(auto) reverse_impl(Xs&& xs) { return foldl(detail::std::forward(xs), nil(), flip(cons)); @@ -268,15 +242,6 @@ namespace boost { namespace hana { return take(minus(to, from), drop(from, detail::std::forward(xs))); } - template - static constexpr decltype(auto) snoc_impl(Xs&& xs, X&& x) { - return foldr( - detail::std::forward(xs), - lift(detail::std::forward(x)), - cons - ); - } - template static constexpr decltype(auto) sort_impl(Xs&& xs) { return sort_by(less, detail::std::forward(xs)); diff --git a/include/boost/hana/maybe.hpp b/include/boost/hana/maybe.hpp index e52abb542..38eeb5ea0 100644 --- a/include/boost/hana/maybe.hpp +++ b/include/boost/hana/maybe.hpp @@ -27,6 +27,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include @@ -205,6 +206,26 @@ namespace boost { namespace hana { } }; + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// + template <> + struct concat_impl { + template + static constexpr auto apply(_nothing, Y&& y) + { return detail::std::forward(y); } + + template + static constexpr auto apply(X&& x, Y const&) + { return detail::std::forward(x); } + }; + + template <> + struct nil_impl { + static constexpr auto apply() + { return nothing; } + }; + ////////////////////////////////////////////////////////////////////////// // Traversable ////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/hana/monad_plus.hpp b/include/boost/hana/monad_plus.hpp new file mode 100644 index 000000000..0224c9a3c --- /dev/null +++ b/include/boost/hana/monad_plus.hpp @@ -0,0 +1,217 @@ +/*! +@file +Defines `boost::hana::MonadPlus`. + +@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_MONAD_PLUS_HPP +#define BOOST_HANA_MONAD_PLUS_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace hana { + ////////////////////////////////////////////////////////////////////////// + // concat + ////////////////////////////////////////////////////////////////////////// + template + struct concat_impl : concat_impl> { }; + + template + struct concat_impl> : default_ { + template + static constexpr void apply(Xs&&, Ys&&) { + static_assert(wrong, Xs, Ys>{}, + "no definition of boost::hana::concat for the given data type"); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // nil + ////////////////////////////////////////////////////////////////////////// + template + struct nil_impl : nil_impl> { }; + + template + struct nil_impl> : default_ { + template + static constexpr void apply(Nothing&& ...) { + static_assert(wrong, Nothing...>{}, + "no definition of boost::hana::nil for the given data type"); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // prepend + ////////////////////////////////////////////////////////////////////////// + template + struct prepend_impl : prepend_impl> { }; + + template + struct prepend_impl> : default_ { + template + static constexpr decltype(auto) apply(X&& x, Xs&& xs) { + return hana::concat(lift(detail::std::forward(x)), + detail::std::forward(xs)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // append + ////////////////////////////////////////////////////////////////////////// + template + struct append_impl : append_impl> { }; + + template + struct append_impl> : default_ { + template + static constexpr decltype(auto) apply(Xs&& xs, X&& x) { + return hana::concat(detail::std::forward(xs), + lift(detail::std::forward(x))); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // filter + ////////////////////////////////////////////////////////////////////////// + template + struct filter_impl : filter_impl> { }; + + template + struct filter_impl> : default_ { + struct go { + template + constexpr decltype(auto) operator()(Pred&& pred, X&& x) const { + decltype(auto) cond = detail::std::forward(pred)(x); + return hana::if_(detail::std::forward(cond), + lift(detail::std::forward(x)), + nil() + ); + } + }; + + template + static constexpr decltype(auto) apply(Xs&& xs, Pred&& pred) { + return hana::bind(detail::std::forward(xs), + hana::partial(go{}, detail::std::forward(pred)) + ); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // cycle + ////////////////////////////////////////////////////////////////////////// + template + struct cycle_impl : cycle_impl> { }; + + namespace mdetail { + template + struct cycle_helper; + + template + struct cycle_helper { + template + static constexpr decltype(auto) apply(Xs const&) + { return nil(); } + }; + + template + struct cycle_helper { + template + static constexpr decltype(auto) apply(Xs const& xs) + { return cycle_helper::apply(hana::concat(xs, xs)); } + }; + + template + struct cycle_helper { + template + static constexpr decltype(auto) apply(Xs const& xs) + { return hana::concat(xs, cycle_helper::apply(xs)); } + }; + } + + template + struct cycle_impl> : default_ { + template + static constexpr decltype(auto) apply(N n, Xs const& xs) { + constexpr detail::std::size_t n_ = hana::value(n); + return mdetail::cycle_helper::apply(xs); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // repeat + ////////////////////////////////////////////////////////////////////////// + template + struct repeat_impl : repeat_impl> { }; + + template + struct repeat_impl> : default_ { + template + static constexpr decltype(auto) apply(N&& n, X&& x) { + return hana::cycle(detail::std::forward(n), + lift(detail::std::forward(x))); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // prefix + ////////////////////////////////////////////////////////////////////////// + template + struct prefix_impl : prefix_impl> { }; + + template + struct prefix_impl> : default_ { + template + static constexpr decltype(auto) apply(Z&& z, Xs&& xs) { + return hana::bind(detail::std::forward(xs), + hana::partial(append, lift(detail::std::forward(z)))); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // suffix + ////////////////////////////////////////////////////////////////////////// + template + struct suffix_impl : suffix_impl> { }; + + template + struct suffix_impl> : default_ { + template + static constexpr decltype(auto) apply(Z&& z, Xs&& xs) { + return hana::bind(detail::std::forward(xs), + hana::partial(hana::flip(prepend), + lift(detail::std::forward(z)))); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // models + ////////////////////////////////////////////////////////////////////////// + template + struct models + : detail::std::integral_constant>{} && + !is_default>{} + > + { }; +}} // end namespace boost::hana + +#endif // !BOOST_HANA_MONAD_PLUS_HPP diff --git a/include/boost/hana/sandbox/lambda_tuple.hpp b/include/boost/hana/sandbox/lambda_tuple.hpp index c41fc31de..454bae847 100644 --- a/include/boost/hana/sandbox/lambda_tuple.hpp +++ b/include/boost/hana/sandbox/lambda_tuple.hpp @@ -16,6 +16,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include @@ -135,17 +136,6 @@ namespace boost { namespace hana { ////////////////////////////////////////////////////////////////////////// // Iterable ////////////////////////////////////////////////////////////////////////// - - //! Instance of `Iterable` for `Tuple`s. - //! - //! `Tuple` is an `Iterable` in the most obvious way. The head of a - //! non-empty tuple corresponds to its first element. The tail of a - //! non-empty tuple is a tuple containing all the elements in the same - //! order, except the head. Finally, a tuple is empty if and only if - //! it has no elements in it. - //! - //! ### Example - //! @snippet example/list/iterable.cpp main template <> struct head_impl { template @@ -203,36 +193,13 @@ namespace boost { namespace hana { } }; - - //! Instance of `List` for the `Tuple` data type. - //! - //! @todo - //! Use perfect forwarding everywhere possible. + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance : List::mcd { - static BOOST_HANA_CONSTEXPR_LAMBDA decltype(auto) nil_impl() { - return sandbox::lambda_tuple(); - } - - template - static constexpr decltype(auto) cons_impl(X&& x, Xs&& xs) { - return detail::std::forward(xs).storage( - [x(detail::std::forward(x))](auto&& ...xs) -> decltype(auto) { - return sandbox::lambda_tuple( - detail::std::move(x), - detail::std::forward(xs)... - ); - } - ); - } - - template - static constexpr decltype(auto) make_impl(Xs&& ...xs) { - return sandbox::lambda_tuple(detail::std::forward(xs)...); - } - + struct concat_impl { template - static constexpr decltype(auto) concat_impl(Xs&& xs, Ys&& ys) { + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { return detail::std::forward(xs).storage( [ys(detail::std::forward(ys))](auto&& ...xs) -> decltype(auto) { return detail::std::move(ys).storage( @@ -248,18 +215,27 @@ namespace boost { namespace hana { } ); } + }; - template - static constexpr decltype(auto) init_impl(Xs&& xs) { - return unpack(range(size_t<0>, pred(length(xs))), - on(sandbox::lambda_tuple, [&xs](auto index) -> decltype(auto) { - return at(index, detail::std::forward(xs)); - }) + template <> + struct prepend_impl { + template + static constexpr decltype(auto) apply(X&& x, Xs&& xs) { + return detail::std::forward(xs).storage( + [x(detail::std::forward(x))](auto&& ...xs) -> decltype(auto) { + return sandbox::lambda_tuple( + detail::std::move(x), + detail::std::forward(xs)... + ); + } ); } + }; + template <> + struct append_impl { template - static constexpr decltype(auto) snoc_impl(Xs&& xs, X&& x) { + static constexpr decltype(auto) apply(Xs&& xs, X&& x) { return detail::std::forward(xs).storage( [x(detail::std::forward(x))](auto&& ...xs) -> decltype(auto) { return sandbox::lambda_tuple( @@ -269,6 +245,33 @@ namespace boost { namespace hana { } ); } + }; + + template <> + struct nil_impl { + static BOOST_HANA_CONSTEXPR_LAMBDA decltype(auto) apply() { + return sandbox::lambda_tuple(); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // List + ////////////////////////////////////////////////////////////////////////// + template <> + struct List::instance : List::mcd { + template + static constexpr decltype(auto) make_impl(Xs&& ...xs) { + return sandbox::lambda_tuple(detail::std::forward(xs)...); + } + + template + static constexpr decltype(auto) init_impl(Xs&& xs) { + return unpack(range(size_t<0>, pred(length(xs))), + on(sandbox::lambda_tuple, [&xs](auto index) -> decltype(auto) { + return at(index, detail::std::forward(xs)); + }) + ); + } template static constexpr decltype(auto) take_impl(N n, Xs&& xs) { diff --git a/include/boost/hana/tuple.hpp b/include/boost/hana/tuple.hpp index 419d8eab4..432c3632c 100644 --- a/include/boost/hana/tuple.hpp +++ b/include/boost/hana/tuple.hpp @@ -33,6 +33,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include @@ -414,25 +415,6 @@ namespace boost { namespace hana { struct List::instance : List::mcd { - static constexpr _tuple<> nil_impl() - { return {}; } - - // cons - /////////////// - #define BOOST_HANA_PP_CONS(REF) \ - template \ - static constexpr _tuple< \ - typename detail::std::decay::type, typename Xs::get_type... \ - > cons_impl(X&& x, detail::closure_impl REF xs) { \ - return { \ - detail::std::forward(x), static_cast(xs).get... \ - }; \ - } \ - /**/ - BOOST_HANA_PP_FOR_EACH_REF1(BOOST_HANA_PP_CONS) - #undef BOOST_HANA_PP_CONS - - // init /////////////// template @@ -550,22 +532,6 @@ namespace boost { namespace hana { ); } - // snoc - /////////////// - #define BOOST_HANA_PP_SNOC(REF) \ - template \ - static constexpr _tuple< \ - typename Xs::get_type..., typename detail::std::decay::type \ - > snoc_impl(detail::closure_impl REF xs, X&& x) { \ - return { \ - static_cast(xs).get..., \ - detail::std::forward(x) \ - }; \ - } \ - /**/ - BOOST_HANA_PP_FOR_EACH_REF1(BOOST_HANA_PP_SNOC) - #undef BOOST_HANA_PP_SNOC - // take /////////////// @@ -758,7 +724,6 @@ namespace boost { namespace hana { } }; -#if 0 ////////////////////////////////////////////////////////////////////////// // MonadPlus ////////////////////////////////////////////////////////////////////////// @@ -851,6 +816,7 @@ namespace boost { namespace hana { #undef BOOST_HANA_PP_APPEND }; +#if 0 ////////////////////////////////////////////////////////////////////////// // Sequence ////////////////////////////////////////////////////////////////////////// diff --git a/test/include/test/auto/list.hpp b/test/include/test/auto/list.hpp index 0adbc048e..2f9135221 100644 --- a/test/include/test/auto/list.hpp +++ b/test/include/test/auto/list.hpp @@ -64,6 +64,13 @@ namespace boost { namespace hana { namespace test { using list_detail::ord; using list_detail::invalid; constexpr struct { } undefined{}; + auto is = [](auto x) { + return [=](auto y) { return equal(x, y); }; + }; + + auto isnt = [](auto x) { + return [=](auto y) { return not_equal(x, y); }; + }; // Check for basic data type consistency { @@ -137,13 +144,6 @@ namespace boost { namespace hana { namespace test { { constexpr struct { } undefined{}; auto prod = test::minimal_product; - auto is = [](auto x) { - return [=](auto y) { return equal(x, y); }; - }; - - auto isnt = [](auto x) { - return [=](auto y) { return not_equal(x, y); }; - }; // make (that's tautological given our definition of `list`, but w/e) @@ -170,109 +170,6 @@ namespace boost { namespace hana { namespace test { )); } - // cons - { - { - BOOST_HANA_CONSTANT_CHECK(equal( - cons(x<0>, list()), - list(x<0>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - cons(x<0>, list(x<1>)), - list(x<0>, x<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - cons(x<0>, list(x<1>, x<2>)), - list(x<0>, x<1>, x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - cons(x<0>, list(x<1>, x<2>, x<3>)), - list(x<0>, x<1>, x<2>, x<3>) - )); - } - - { - BOOST_HANA_CONSTEXPR_CHECK(equal( - cons(1, list()), list(1) - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - cons(1, list('2')), list(1, '2') - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - cons(1, list('2', 3.3)), list(1, '2', 3.3) - )); - } - } - - // nil - { - BOOST_HANA_CONSTANT_CHECK(equal( - nil(), list() - )); - } - - // concat - { - { - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(), list()), - list() - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(), list(x<0>)), - list(x<0>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(), list(x<0>, x<1>)), - list(x<0>, x<1>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>), list()), - list(x<0>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>), list(x<1>)), - list(x<0>, x<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>), list(x<1>, x<2>)), - list(x<0>, x<1>, x<2>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>, x<1>), list()), - list(x<0>, x<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>, x<1>), list(x<2>)), - list(x<0>, x<1>, x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(x<0>, x<1>), list(x<2>, x<3>)), - list(x<0>, x<1>, x<2>, x<3>) - )); - } - - { - BOOST_HANA_CONSTANT_CHECK(equal( - concat(list(), list()), list() - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - concat(list(1), list()), list(1) - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - concat(list(), list(1)), list(1) - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - concat(list(1), list('2')), list(1, '2') - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - concat(list(1, '2'), list(3.3)), list(1, '2', 3.3) - )); - } - } - // init { { @@ -385,36 +282,6 @@ namespace boost { namespace hana { namespace test { )); } - // snoc - { - { - BOOST_HANA_CONSTANT_CHECK(equal( - snoc(list(), x<0>), - list(x<0>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - snoc(list(x<0>), x<1>), - list(x<0>, x<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - snoc(list(x<0>, x<1>), x<2>), - list(x<0>, x<1>, x<2>) - )); - } - - { - BOOST_HANA_CONSTEXPR_CHECK(equal( - snoc(list(), 1), list(1) - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - snoc(list(1), '2'), list(1, '2') - )); - BOOST_HANA_CONSTEXPR_CHECK(equal( - snoc(list(1, '2'), 3.3), list(1, '2', 3.3) - )); - } - } - // take { BOOST_HANA_CONSTANT_CHECK(equal( @@ -568,39 +435,6 @@ namespace boost { namespace hana { namespace test { )); } - // repeat - { - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<0>, x<0>), - list() - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<1>, x<0>), - list(x<0>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<2>, x<0>), - list(x<0>, x<0>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<3>, x<0>), - list(x<0>, x<0>, x<0>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<4>, x<0>), - list(x<0>, x<0>, x<0>, x<0>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - repeat(int_<5>, x<0>), - list(x<0>, x<0>, x<0>, x<0>, x<0>) - )); - } - // reverse { { @@ -902,63 +736,6 @@ namespace boost { namespace hana { namespace test { ); } - // filter - { - auto z = x<999>; - - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(), isnt(z)), - list() - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(z), isnt(z)), - list() - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>), isnt(z)), - list(x<1>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>, x<2>), isnt(z)), - list(x<1>, x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(z, x<2>), isnt(z)), - list(x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>, z), isnt(z)), - list(x<1>) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(z, x<2>, x<3>), isnt(z)), - list(x<2>, x<3>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>, z, x<3>), isnt(z)), - list(x<1>, x<3>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>, x<2>, z), isnt(z)), - list(x<1>, x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(x<1>, z, z), isnt(z)), - list(x<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(z, x<2>, z), isnt(z)), - list(x<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - filter(list(z, z, x<3>), isnt(z)), - list(x<3>) - )); - } - // group { BOOST_HANA_CONSTANT_CHECK(equal( @@ -1488,7 +1265,9 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Functor instance + ////////////////////////////////////////////////////////////////////// { laws(); @@ -1572,7 +1351,9 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Applicative instance + ////////////////////////////////////////////////////////////////////// { laws(); @@ -1641,7 +1422,9 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Monad instance + ////////////////////////////////////////////////////////////////////// { laws(); @@ -1675,10 +1458,12 @@ namespace boost { namespace hana { namespace test { )); } - // ... + //! @todo Finish this } + ////////////////////////////////////////////////////////////////////// // Traversable instance + ////////////////////////////////////////////////////////////////////// { laws(); @@ -1732,7 +1517,9 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Comparable instance + ////////////////////////////////////////////////////////////////////// { laws(); using test::x; @@ -1771,10 +1558,12 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Foldable // // Foldable is actually provided by Iterable, but it is very easy for // us to check that instance. + ////////////////////////////////////////////////////////////////////// { laws(); @@ -2562,10 +2351,12 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Searchable // // Searchable is actually provided by Iterable, but it is very easy // for us to check that instance. + ////////////////////////////////////////////////////////////////////// { laws(); @@ -2835,12 +2626,14 @@ namespace boost { namespace hana { namespace test { } } + ////////////////////////////////////////////////////////////////////// // Iterable // // While List does not _provide_ an instance for Iterable, it requires // any instance to also instantiate Iterable. Furthermore, since all List // instances are isomorphic, it is possible to check the Iterable instance // of any List. + ////////////////////////////////////////////////////////////////////// { laws(); @@ -3108,6 +2901,370 @@ namespace boost { namespace hana { namespace test { )); } } + + ////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////// + { + laws(); + + // nil + { + BOOST_HANA_CONSTANT_CHECK(equal( + nil(), list() + )); + } + + // concat + { + { + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(), list()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(), list(x<0>)), + list(x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(), list(x<0>, x<1>)), + list(x<0>, x<1>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>), list()), + list(x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>), list(x<1>)), + list(x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>), list(x<1>, x<2>)), + list(x<0>, x<1>, x<2>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>, x<1>), list()), + list(x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>, x<1>), list(x<2>)), + list(x<0>, x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(x<0>, x<1>), list(x<2>, x<3>)), + list(x<0>, x<1>, x<2>, x<3>) + )); + } + + { + BOOST_HANA_CONSTANT_CHECK(equal( + concat(list(), list()), list() + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + concat(list(1), list()), list(1) + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + concat(list(), list(1)), list(1) + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + concat(list(1), list('2')), list(1, '2') + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + concat(list(1, '2'), list(3.3)), list(1, '2', 3.3) + )); + } + } + + // filter + { + auto z = x<999>; + + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(), isnt(z)), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(z), isnt(z)), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>), isnt(z)), + list(x<1>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>, x<2>), isnt(z)), + list(x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(z, x<2>), isnt(z)), + list(x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>, z), isnt(z)), + list(x<1>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(z, x<2>, x<3>), isnt(z)), + list(x<2>, x<3>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>, z, x<3>), isnt(z)), + list(x<1>, x<3>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>, x<2>, z), isnt(z)), + list(x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(x<1>, z, z), isnt(z)), + list(x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(z, x<2>, z), isnt(z)), + list(x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + filter(list(z, z, x<3>), isnt(z)), + list(x<3>) + )); + } + + // prepend + { + { + BOOST_HANA_CONSTANT_CHECK(equal( + prepend(x<0>, list()), + list(x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + prepend(x<0>, list(x<1>)), + list(x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + prepend(x<0>, list(x<1>, x<2>)), + list(x<0>, x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + prepend(x<0>, list(x<1>, x<2>, x<3>)), + list(x<0>, x<1>, x<2>, x<3>) + )); + } + + { + BOOST_HANA_CONSTEXPR_CHECK(equal( + prepend(1, list()), list(1) + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + prepend(1, list('2')), list(1, '2') + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + prepend(1, list('2', 3.3)), list(1, '2', 3.3) + )); + } + } + + // append + { + { + BOOST_HANA_CONSTANT_CHECK(equal( + append(list(), x<0>), + list(x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + append(list(x<0>), x<1>), + list(x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + append(list(x<0>, x<1>), x<2>), + list(x<0>, x<1>, x<2>) + )); + } + + { + BOOST_HANA_CONSTEXPR_CHECK(equal( + append(list(), 1), list(1) + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + append(list(1), '2'), list(1, '2') + )); + BOOST_HANA_CONSTEXPR_CHECK(equal( + append(list(1, '2'), 3.3), list(1, '2', 3.3) + )); + } + } + + // cycle + { + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<0>, list()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<1>, list()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<2>, list()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<3>, list()), + list() + )); + + + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<0>, list(x<0>)), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<1>, list(x<0>)), + list(x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<2>, list(x<0>)), + list(x<0>, x<0>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<3>, list(x<0>)), + list(x<0>, x<0>, x<0>) + )); + + + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<0>, list(x<0>, x<1>)), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<1>, list(x<0>, x<1>)), + list(x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<2>, list(x<0>, x<1>)), + list(x<0>, x<1>, x<0>, x<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<3>, list(x<0>, x<1>)), + list(x<0>, x<1>, x<0>, x<1>, x<0>, x<1>) + )); + + + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<0>, list(x<0>, x<1>, x<2>)), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<1>, list(x<0>, x<1>, x<2>)), + list(x<0>, x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<2>, list(x<0>, x<1>, x<2>)), + list(x<0>, x<1>, x<2>, x<0>, x<1>, x<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + cycle(size_t<3>, list(x<0>, x<1>, x<2>)), + list(x<0>, x<1>, x<2>, x<0>, x<1>, x<2>, x<0>, x<1>, x<2>) + )); + } + + // repeat + { + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<0>, x<0>), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<1>, x<0>), + list(x<0>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<2>, x<0>), + list(x<0>, x<0>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<3>, x<0>), + list(x<0>, x<0>, x<0>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<4>, x<0>), + list(x<0>, x<0>, x<0>, x<0>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + repeat(size_t<5>, x<0>), + list(x<0>, x<0>, x<0>, x<0>, x<0>) + )); + } + + // prefix + { + auto z = x<999>; + + BOOST_HANA_CONSTANT_CHECK(equal( + prefix(z, list()), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + prefix(z, list(x<0>)), + list(z, x<0>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + prefix(z, list(x<0>, x<1>)), + list(z, x<0>, z, x<1>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + prefix(z, list(x<0>, x<1>, x<2>)), + list(z, x<0>, z, x<1>, z, x<2>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + prefix(z, list(x<0>, x<1>, x<2>, x<3>)), + list(z, x<0>, z, x<1>, z, x<2>, z, x<3>) + )); + } + + // suffix + { + auto z = x<999>; + + BOOST_HANA_CONSTANT_CHECK(equal( + suffix(z, list()), + list() + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + suffix(z, list(x<0>)), + list(x<0>, z) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + suffix(z, list(x<0>, x<1>)), + list(x<0>, z, x<1>, z) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + suffix(z, list(x<0>, x<1>, x<2>)), + list(x<0>, z, x<1>, z, x<2>, z) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + suffix(z, list(x<0>, x<1>, x<2>, x<3>)), + list(x<0>, z, x<1>, z, x<2>, z, x<3>, z) + )); + } + } }; }}} // end namespace boost::hana::test diff --git a/test/include/test/auto/monad_plus.hpp b/test/include/test/auto/monad_plus.hpp new file mode 100644 index 000000000..0e0883d89 --- /dev/null +++ b/test/include/test/auto/monad_plus.hpp @@ -0,0 +1,68 @@ +/* +@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_TEST_TEST_AUTO_MONAD_PLUS_HPP +#define BOOST_HANA_TEST_TEST_AUTO_MONAD_PLUS_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace boost { namespace hana { namespace test { + template + auto laws = [] { + laws(); + static_assert(models{}, ""); + + auto f = compose(lift, injection([]{})); + + for_each(objects, [=](auto a) { + for_each(objects, [=](auto b) { + for_each(objects, [=](auto c) { + // left identity + BOOST_HANA_CHECK(equal( + concat(nil(), a), + a + )); + + // right identity + BOOST_HANA_CHECK(equal( + concat(a, nil()), + a + )); + + // associativity + BOOST_HANA_CHECK(equal( + concat(a, concat(b, c)), + concat(concat(a, b), c) + )); + + // absorption + BOOST_HANA_CHECK(equal( + bind(nil(), f), + nil() + )); + + BOOST_HANA_CHECK(equal( + bind(a, always(nil())), + nil() + )); + });});}); + }; +}}} // end namespace boost::hana::test + +#endif // !BOOST_HANA_TEST_TEST_AUTO_MONAD_PLUS_HPP diff --git a/test/include/test/seq.hpp b/test/include/test/seq.hpp index 194282206..c3f6f0dba 100644 --- a/test/include/test/seq.hpp +++ b/test/include/test/seq.hpp @@ -7,13 +7,13 @@ Distributed under the Boost Software License, Version 1.0. #ifndef BOOST_HANA_TEST_TEST_SEQ_HPP #define BOOST_HANA_TEST_TEST_SEQ_HPP +#include #include #include - -// instances #include #include #include +#include #include @@ -140,18 +140,35 @@ namespace boost { namespace hana { } }; + ////////////////////////////////////////////////////////////////////////// + // Applicative + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance : List::mcd { - template - static constexpr auto cons_impl(X x, Xs xs) { + struct lift_impl { + template + static constexpr auto apply(X x) + { return test::seq(x); } + }; + + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// + template <> + struct concat_impl { + template + static constexpr auto apply(Xs xs, Ys ys) { return xs.storage([=](auto ...xs) { - return test::seq(x, xs...); + return ys.storage([=](auto ...ys) { + return test::seq(xs..., ys...); + }); }); } + }; - static BOOST_HANA_CONSTEXPR_LAMBDA auto nil_impl() { - return test::seq(); - } + template <> + struct nil_impl { + static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() + { return test::seq(); } }; }} // end namespace boost::hana diff --git a/test/maybe.cpp b/test/maybe.cpp index 3abf328d3..0c2788ca7 100644 --- a/test/maybe.cpp +++ b/test/maybe.cpp @@ -19,6 +19,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ namespace boost { namespace hana { namespace test { type, type, type, + type, type, type, @@ -185,6 +187,32 @@ int main() { } } + // MonadPlus + { + using test::x; + + // nil + { + BOOST_HANA_CONSTANT_CHECK(equal(nil(), nothing)); + } + + // concat + { + auto rv_nothing = [] { return nothing; }; // rvalue nothing + + BOOST_HANA_CONSTANT_CHECK(equal(concat(rv_nothing(), nothing), nothing)); + BOOST_HANA_CONSTANT_CHECK(equal(concat(nothing, rv_nothing()), nothing)); + BOOST_HANA_CONSTANT_CHECK(equal(concat(rv_nothing(), rv_nothing()), nothing)); + BOOST_HANA_CONSTANT_CHECK(equal(concat(rv_nothing(), just(x<0>)), just(x<0>))); + BOOST_HANA_CONSTANT_CHECK(equal(concat(just(x<0>), rv_nothing()), just(x<0>))); + + BOOST_HANA_CONSTANT_CHECK(equal(concat(nothing, nothing), nothing)); + BOOST_HANA_CONSTANT_CHECK(equal(concat(nothing, just(x<0>)), just(x<0>))); + BOOST_HANA_CONSTANT_CHECK(equal(concat(just(x<0>), nothing), just(x<0>))); + BOOST_HANA_CONSTANT_CHECK(equal(concat(just(x<0>), just(x<1>)), just(x<0>))); + } + } + // Traversable { auto f = test::injection([]{}); diff --git a/test/sandbox/repeat.cpp b/test/sandbox/repeat.cpp index fed8445c5..b593e3f74 100644 --- a/test/sandbox/repeat.cpp +++ b/test/sandbox/repeat.cpp @@ -11,6 +11,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include using namespace boost::hana; @@ -64,15 +65,33 @@ namespace boost { namespace hana { { return true_; } }; + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance : List::mcd { - static constexpr auto nil_impl() - { return lazy_nil; } + struct concat_impl { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; + template <> + struct prepend_impl { template - static constexpr auto cons_impl(X x, Xs xs) + static constexpr auto apply(X x, Xs xs) { return lazy_cons(x, lazy(xs)); } }; + + template <> + struct nil_impl { + static constexpr auto apply() + { return lazy_nil; } + }; }} diff --git a/test/sandbox/tuple_opts.cpp b/test/sandbox/tuple_opts.cpp index 9b0d656f1..50635eeca 100644 --- a/test/sandbox/tuple_opts.cpp +++ b/test/sandbox/tuple_opts.cpp @@ -128,13 +128,23 @@ namespace boost { namespace hana { { return bool_; } }; + ////////////////////////////////////////////////////////////////////////// + // MonadPlus + ////////////////////////////////////////////////////////////////////////// template <> - struct List::instance< ::Tuple> : List::mcd< ::Tuple> { - // nil - static BOOST_HANA_CONSTEXPR_LAMBDA auto nil_impl() - { return ::tuple(); } + struct concat_impl< ::Tuple> { + template + static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) { + return hana::foldr( + detail::std::forward(xs), + detail::std::forward(ys), + prepend + ); + } + }; - // cons + template <> + struct prepend_impl< ::Tuple> { template static constexpr auto cons_helper(X x, Xs xs, Datatype) { return unpack(xs, [=](auto ...xs) { return ::tuple(x, xs...); }); } @@ -159,11 +169,21 @@ namespace boost { namespace hana { template - static constexpr auto cons_impl(X x, Xs xs) + static constexpr auto apply(X x, Xs xs) { return cons_helper(x, xs, datatype_t{}); } + }; + template <> + struct nil_impl< ::Tuple> { + static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() + { return ::tuple(); } + }; - // sort + ////////////////////////////////////////////////////////////////////////// + // List + ////////////////////////////////////////////////////////////////////////// + template <> + struct List::instance< ::Tuple> : List::mcd< ::Tuple> { template static constexpr auto sort_impl(Xs xs) { return List::mcd< ::Tuple>::sort_impl(xs); } diff --git a/test/seq/main.hpp b/test/seq/main.hpp index f6fbb02d9..fbe0c255f 100644 --- a/test/seq/main.hpp +++ b/test/seq/main.hpp @@ -13,13 +13,12 @@ Distributed under the Boost Software License, Version 1.0. #include #include -#include - -// tested instances #include #include #include +#include #include +#include using namespace boost::hana; @@ -30,7 +29,8 @@ namespace boost { namespace hana { type, type, type, - type + type, + type ); template <>