diff --git a/example/core/default_instance.cpp b/example/core/default_instance.cpp new file mode 100644 index 000000000..75526f49f --- /dev/null +++ b/example/core/default_instance.cpp @@ -0,0 +1,45 @@ +/* +@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 +namespace hana = boost::hana; + + +struct Showable { + BOOST_HANA_TYPECLASS(Showable); + struct mcd { }; +}; + +BOOST_HANA_CONSTEXPR_LAMBDA auto show = [](auto x) { + return Showable::instance>::show_impl(x); +}; + +namespace boost { namespace hana { + template <> + struct default_instance : Showable::mcd { + template + static std::string show_impl(X) + { return ""; } + }; +}} + +template <> +struct Showable::instance : Showable::mcd { + static auto show_impl(int i) + { return (std::ostringstream{} << i).str(); } +}; + +struct unshowable { }; + +int main() { + assert(show(1) == "1"); + assert(show(unshowable{}) == ""); +} diff --git a/example/core/typeclass.cpp b/example/core/typeclass.cpp index b5a466292..ac2a78a97 100644 --- a/example/core/typeclass.cpp +++ b/example/core/typeclass.cpp @@ -12,11 +12,8 @@ Distributed under the Boost Software License, Version 1.0. namespace hana = boost::hana; -struct Incrementable; -namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Incrementable) -}} -struct Incrementable : hana::typeclass { +struct Incrementable { + BOOST_HANA_TYPECLASS(Incrementable); struct next_mcd; struct next_n_mcd; }; diff --git a/include/boost/hana/applicative.hpp b/include/boost/hana/applicative.hpp index d146e076f..15369ae18 100644 --- a/include/boost/hana/applicative.hpp +++ b/include/boost/hana/applicative.hpp @@ -15,8 +15,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Applicative) - /*! @ingroup typeclasses `Applicative`s are `Functor`s with the ability to lift values and combine @@ -44,7 +42,8 @@ namespace boost { namespace hana { fmap(f, x) == ap(lift(f), x) @endcode */ - struct Applicative : typeclass { + struct Applicative { + BOOST_HANA_TYPECLASS(Applicative); struct mcd { }; }; diff --git a/include/boost/hana/comparable.hpp b/include/boost/hana/comparable.hpp index 2f55320be..777dc6b37 100644 --- a/include/boost/hana/comparable.hpp +++ b/include/boost/hana/comparable.hpp @@ -16,11 +16,10 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_BINARY_TYPECLASS_BOILERPLATE(struct Comparable) - //! @ingroup typeclasses //! The `Comparable` type class defines equality and inequality. - struct Comparable : binary_typeclass { + struct Comparable { + BOOST_HANA_BINARY_TYPECLASS(Comparable); struct equal_mcd; struct not_equal_mcd; struct laws; diff --git a/include/boost/hana/detail/logical_fwd.hpp b/include/boost/hana/detail/logical_fwd.hpp index 320de1096..6a424e336 100644 --- a/include/boost/hana/detail/logical_fwd.hpp +++ b/include/boost/hana/detail/logical_fwd.hpp @@ -15,8 +15,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Logical) - /*! @ingroup typeclasses The `Logical` type class is for data types acting like a boolean. @@ -31,7 +29,8 @@ namespace boost { namespace hana { We don't short-circuit right now. Don't forget to change the examples and unit tests when that's implemented. */ - struct Logical : typeclass { + struct Logical { + BOOST_HANA_TYPECLASS(Logical); struct mcd; }; diff --git a/include/boost/hana/detail/minimal/monad.hpp b/include/boost/hana/detail/minimal/monad.hpp index 8a827f8d0..b00e320b5 100644 --- a/include/boost/hana/detail/minimal/monad.hpp +++ b/include/boost/hana/detail/minimal/monad.hpp @@ -57,20 +57,18 @@ struct Functor::instance> : Functor::fmap_mcd { { return ap(lift>(f), m); } }; -//! @todo -//! Inherit from Applicative::mcd once Clang is fixed or Core is changed. -template -struct Applicative::instance> { +template +struct Applicative::instance> : Applicative::mcd { template static constexpr auto lift_impl(T t) - { return detail::minimal::monad(t); } + { return detail::minimal::monad(t); } //! @todo //! Use the bind-based implementation which causes infinite recursion //! right now. template static constexpr auto ap_impl(AF af, AX ax) { - return detail::minimal::monad(af.value(ax.value)); + return detail::minimal::monad(af.value(ax.value)); // return bind(af, [=](auto f) { // return bind(ax, [=](auto x) { // return lift>(f(x)); diff --git a/include/boost/hana/detail/sandbox/boolean.hpp b/include/boost/hana/detail/sandbox/boolean.hpp index 772661d7d..894aa81f1 100644 --- a/include/boost/hana/detail/sandbox/boolean.hpp +++ b/include/boost/hana/detail/sandbox/boolean.hpp @@ -15,8 +15,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Boolean) - //! @ingroup typeclasses //! The `Boolean` type class defines a //! [boolean algebra](http://en.wikipedia.org/wiki/Boolean_algebra_(structure)). @@ -34,7 +32,8 @@ namespace boost { namespace hana { //! //! ## Laws //! ... - struct Boolean : typeclass { + struct Boolean { + BOOST_HANA_TYPECLASS(Boolean); struct mcd { }; }; diff --git a/include/boost/hana/detail/sandbox/monad_zero.hpp b/include/boost/hana/detail/sandbox/monad_zero.hpp index 9bb57022e..a4d554a2e 100644 --- a/include/boost/hana/detail/sandbox/monad_zero.hpp +++ b/include/boost/hana/detail/sandbox/monad_zero.hpp @@ -18,8 +18,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct MonadZero) - //! @ingroup typeclasses //! `Monad`s with a neutral element. //! @@ -28,7 +26,8 @@ namespace boost { namespace hana { //! //! ## Laws //! ... - struct MonadZero : typeclass { + struct MonadZero { + BOOST_HANA_TYPECLASS(MonadZero); template struct mcd; }; diff --git a/include/boost/hana/detail/sandbox/pattern.hpp b/include/boost/hana/detail/sandbox/pattern.hpp index fa24f42bc..d444bbd6c 100644 --- a/include/boost/hana/detail/sandbox/pattern.hpp +++ b/include/boost/hana/detail/sandbox/pattern.hpp @@ -15,8 +15,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Pattern) - //! @ingroup typeclasses //! ... //! @@ -37,7 +35,8 @@ namespace boost { namespace hana { //! A lazy action could be anything that can be called with `id`; this //! would allow us to create lazy lambdas on the fly and also to use //! `lazy()` when we want to. - struct Pattern : typeclass { + struct Pattern { + BOOST_HANA_TYPECLASS(Pattern); struct mcd { }; }; diff --git a/include/boost/hana/detail/sandbox/traversable.hpp b/include/boost/hana/detail/sandbox/traversable.hpp index 1392e7693..845617133 100644 --- a/include/boost/hana/detail/sandbox/traversable.hpp +++ b/include/boost/hana/detail/sandbox/traversable.hpp @@ -15,8 +15,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Traversable) - /*! @ingroup typeclasses `Traversable` represents types that can be folded in a @@ -27,7 +25,8 @@ namespace boost { namespace hana { ## Laws */ - struct Traversable : typeclass { + struct Traversable { + BOOST_HANA_TYPECLASS(Traversable); struct traverse_mcd; }; diff --git a/include/boost/hana/detail/typeclasses.hpp b/include/boost/hana/detail/typeclasses.hpp index 321c58ace..b5139ee66 100644 --- a/include/boost/hana/detail/typeclasses.hpp +++ b/include/boost/hana/detail/typeclasses.hpp @@ -11,51 +11,41 @@ Distributed under the Boost Software License, Version 1.0. #define BOOST_HANA_DETAIL_TYPECLASSES_HPP namespace boost { namespace hana { + namespace core_detail { + template + struct dependent { using type = x; }; + } + //! @ingroup core //! Machinery for creating a unary type class. //! //! //! ### Creating a type class - //! Creating a new type class is done by inheriting from `typeclass`: + //! Creating a new type class is done by using the `BOOST_HANA_TYPECLASS` + //! macro inside a struct with the desired name: //! @code - //! struct Typeclass : typeclass { }; + //! struct Typeclass { + //! BOOST_HANA_TYPECLASS(Typeclass); + //! }; //! @endcode //! - //! If desired, default methods can be provided by putting them inside - //! a nested type of `Typeclass`: + //! If desired, methods can be provided by putting them inside a nested + //! type of `Typeclass`: //! @code - //! struct Typeclass : typeclass { + //! struct Typeclass { + //! BOOST_HANA_TYPECLASS(Typeclass); //! struct some_member { - //! // default methods + //! // methods //! }; //! }; //! @endcode //! //! In this library, type classes with a single minimal complete definition - //! provide their default methods, if any, in the nested type named `mcd`. - //! In the case where multiple minimal complete definitions exist, each set - //! of default methods is in a different nested type with a descriptive - //! name. In all cases, the minimal complete definition(s) and the location - //! of their associated set of default methods are documented. - //! - //! One can also provide a default instance for all data types by defining - //! a `default_` member: - //! @code - //! struct Typeclass : typeclass { - //! struct default_ { - //! // default instance for all data types - //! }; - //! }; - //! @endcode - //! - //! `default_` should be just like a normal instance; see below for how - //! to instantiate a type class. This can be used to provide a default - //! behavior for all data types while still allowing this behavior to - //! be customized by instantiating the type class. However, this should - //! seldom be used because methods with a meaningful behavior for all - //! data types are rare. This feature is provided for flexibility, but - //! it should be a hint to reconsider your type class design if you are - //! about to use it. + //! provide the other methods, if any, in the nested type named `mcd`. In + //! the case where multiple minimal complete definitions exist, each set of + //! provided methods is in a different nested type with a descriptive name. + //! In all cases, the minimal complete definition(s) and the location of + //! their associated set of provided methods are documented. //! //! //! ### Instantiating a type class @@ -108,8 +98,28 @@ namespace boost { namespace hana { //! //! ### Example //! @include example/core/typeclass.cpp - template - struct typeclass; + #define BOOST_HANA_TYPECLASS(NAME) \ + template \ + struct instance \ + : ::boost::hana::core_detail::dependent< \ + ::boost::hana::default_instance, Enable \ + >::type \ + { } \ + /**/ + + //! @ingroup core + //! Machinery for creating a binary type class. + //! + //! This is equivalent to `BOOST_HANA_TYPECLASS`, except it creates a type + //! class with two arguments. + #define BOOST_HANA_BINARY_TYPECLASS(NAME) \ + template \ + struct instance \ + : ::boost::hana::core_detail::dependent< \ + ::boost::hana::default_instance, Enable \ + >::type \ + { } \ + /**/ //! @ingroup core //! Explicitly disable a type class instance. @@ -122,42 +132,31 @@ namespace boost { namespace hana { //! @include example/core/disable.cpp struct disable { }; - namespace core_detail { - template - struct dependent { using type = x; }; - } - - #define BOOST_HANA_TYPECLASS_BOILERPLATE(NAME) \ - template <> \ - struct typeclass { \ - using default_ = disable; \ - \ - template \ - struct instance \ - : core_detail::dependent::type::default_ \ - { }; \ - }; \ - /**/ - //! @ingroup core - //! Machinery for creating a binary type class. + //! Defines a default instance for the given type class. //! - //! This is equivalent to `typeclass`, except it creates a type class - //! with two arguments. + //! To define a default instance for all data types, specialize the + //! `default_instance` template for the desired type class: + //! @code + //! template <> + //! struct default_instance { + //! // default instance for all data types + //! }; + //! @endcode + //! + //! `default_instance` should be just like a normal instance; see below + //! for how to instantiate a type class. This can be used to provide a + //! default behavior for all data types while still allowing this behavior + //! to be customized by instantiating the type class. However, this should + //! seldom be used because methods with a meaningful behavior for all + //! data types are rare. This feature is provided for flexibility, but + //! it should be a hint to reconsider your type class design if you are + //! about to use it. + //! + //! ### Example + //! @include example/core/default_instance.cpp template - struct binary_typeclass; - - #define BOOST_HANA_BINARY_TYPECLASS_BOILERPLATE(NAME) \ - template <> \ - struct binary_typeclass { \ - using default_ = disable; \ - \ - template \ - struct instance \ - : core_detail::dependent::type::default_ \ - { }; \ - }; \ - /**/ + struct default_instance : disable { }; namespace core_detail { template diff --git a/include/boost/hana/foldable.hpp b/include/boost/hana/foldable.hpp index fe616a964..577efd386 100644 --- a/include/boost/hana/foldable.hpp +++ b/include/boost/hana/foldable.hpp @@ -22,12 +22,11 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Foldable) - //! @ingroup typeclasses //! Data structures that can be folded, i.e. summarized into //! a single value. - struct Foldable : typeclass { + struct Foldable { + BOOST_HANA_TYPECLASS(Foldable); struct lazy_foldr_mcd; }; diff --git a/include/boost/hana/functor.hpp b/include/boost/hana/functor.hpp index 3603643de..d5829302d 100644 --- a/include/boost/hana/functor.hpp +++ b/include/boost/hana/functor.hpp @@ -17,8 +17,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Functor) - /*! @ingroup typeclasses `Functor` represents types that can be mapped over. @@ -32,7 +30,8 @@ namespace boost { namespace hana { fmap (f . g) == fmap f . fmap g @endcode */ - struct Functor : typeclass { + struct Functor { + BOOST_HANA_TYPECLASS(Functor); struct fmap_mcd; struct adjust_mcd; }; diff --git a/include/boost/hana/iterable.hpp b/include/boost/hana/iterable.hpp index 9f7f5b348..60b31d4fa 100644 --- a/include/boost/hana/iterable.hpp +++ b/include/boost/hana/iterable.hpp @@ -22,8 +22,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Iterable) - /*! @ingroup typeclasses Data structures allowing external iteration. @@ -39,7 +37,8 @@ namespace boost { namespace hana { - Instead of having a lot of methods, maybe some of the functions below should just be implemented as functions using the mcd, as in the MPL11? */ - struct Iterable : typeclass { + struct Iterable { + BOOST_HANA_TYPECLASS(Iterable); struct mcd; struct FoldableInstance; struct ComparableInstance; diff --git a/include/boost/hana/list.hpp b/include/boost/hana/list.hpp index fe366aa28..f507f5b68 100644 --- a/include/boost/hana/list.hpp +++ b/include/boost/hana/list.hpp @@ -37,9 +37,6 @@ namespace boost { namespace hana { ////////////////////////////////////////////////////////////////////////// // The List type class ////////////////////////////////////////////////////////////////////////// - - BOOST_HANA_TYPECLASS_BOILERPLATE(struct List) - /*! @ingroup typeclasses @ingroup datatypes @@ -73,7 +70,8 @@ namespace boost { namespace hana { - There is a strong relationship between this and `MonadPlus`. Actually, they might be just the same. Check this out. */ - struct List : typeclass { + struct List { + BOOST_HANA_TYPECLASS(List); template struct mcd; }; diff --git a/include/boost/hana/monad.hpp b/include/boost/hana/monad.hpp index 3b97d9987..0723827af 100644 --- a/include/boost/hana/monad.hpp +++ b/include/boost/hana/monad.hpp @@ -16,8 +16,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Monad) - /*! @ingroup typeclasses `Monad`s are `Applicative`s with the ability to flatten values that were @@ -33,7 +31,8 @@ namespace boost { namespace hana { bind(m, [](auto x){ return bind(f(x), g); }) == bind(bind(m, f), g) @endcode */ - struct Monad : typeclass { + struct Monad { + BOOST_HANA_TYPECLASS(Monad); struct bind_mcd; struct flatten_mcd; }; diff --git a/include/boost/hana/orderable.hpp b/include/boost/hana/orderable.hpp index 5430425f8..ec0701d40 100644 --- a/include/boost/hana/orderable.hpp +++ b/include/boost/hana/orderable.hpp @@ -16,8 +16,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_BINARY_TYPECLASS_BOILERPLATE(struct Orderable) - /*! @ingroup typeclasses The `Orderable` type class is used for data types defining a @@ -39,7 +37,8 @@ namespace boost { namespace hana { if a ~ b && b ~ c then a ~ c // Transitivity of incomparability @endcode */ - struct Orderable : binary_typeclass { + struct Orderable { + BOOST_HANA_BINARY_TYPECLASS(Orderable); struct less_mcd; }; diff --git a/include/boost/hana/pair.hpp b/include/boost/hana/pair.hpp index a2c126b09..efda83740 100644 --- a/include/boost/hana/pair.hpp +++ b/include/boost/hana/pair.hpp @@ -18,8 +18,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(struct Pair) - /*! @ingroup typeclasses @ingroup datatypes @@ -39,7 +37,8 @@ namespace boost { namespace hana { Provide and document instances for `Functor`, `Applicative`, `Monad` and `Foldable`. */ - struct Pair : typeclass { + struct Pair { + BOOST_HANA_TYPECLASS(Pair); //! Minimal complete definition: `first` and `second` struct mcd { }; }; diff --git a/test/core/disable.cpp b/test/core/disable.cpp index 26b597e55..cfdc624c2 100644 --- a/test/core/disable.cpp +++ b/test/core/disable.cpp @@ -12,11 +12,9 @@ using namespace boost::hana; struct Disabled; -struct Typeclass; -namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Typeclass) -}} -struct Typeclass : typeclass { }; +struct Typeclass { + BOOST_HANA_TYPECLASS(Typeclass); +}; // Instance enabled for all data types. template struct Typeclass::instance { }; diff --git a/test/core/instantiates.cpp b/test/core/instantiates.cpp index 37e7007e4..3c81b4594 100644 --- a/test/core/instantiates.cpp +++ b/test/core/instantiates.cpp @@ -12,11 +12,9 @@ Distributed under the Boost Software License, Version 1.0. using namespace boost::hana; -struct Typeclass; -namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Typeclass) -}} -struct Typeclass : typeclass { }; +struct Typeclass { + BOOST_HANA_TYPECLASS(Typeclass); +}; struct NotInstance; struct Instance; diff --git a/test/core/is_a.cpp b/test/core/is_a.cpp index f08430da6..39458b78d 100644 --- a/test/core/is_a.cpp +++ b/test/core/is_a.cpp @@ -15,11 +15,9 @@ Distributed under the Boost Software License, Version 1.0. using namespace boost::hana; -struct Typeclass; -namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Typeclass) -}} -struct Typeclass : typeclass { }; +struct Typeclass { + BOOST_HANA_TYPECLASS(Typeclass); +}; struct NotInstance; struct Instance; diff --git a/test/core/typeclass.cpp b/test/core/typeclass.cpp index 3d92ab92f..870ae4d73 100644 --- a/test/core/typeclass.cpp +++ b/test/core/typeclass.cpp @@ -10,17 +10,18 @@ Distributed under the Boost Software License, Version 1.0. namespace hana = boost::hana; -struct Typeclass; +struct Typeclass { + BOOST_HANA_TYPECLASS(Typeclass); +}; + namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Typeclass) -}} -struct Typeclass : hana::typeclass { - struct default_ { + template <> + struct default_instance { static constexpr bool has_explicit_instance = false; static constexpr bool has_predicated_instance = false; static constexpr bool has_defaults = true; }; -}; +}} struct ExplicitInstance; struct PredicatedInstance; diff --git a/test/sandbox/logical.cpp b/test/sandbox/logical.cpp index 0bea2ca6b..618a4f768 100644 --- a/test/sandbox/logical.cpp +++ b/test/sandbox/logical.cpp @@ -12,11 +12,6 @@ Distributed under the Boost Software License, Version 1.0. namespace hana = boost::hana; -struct Logical; -namespace boost { namespace hana { - BOOST_HANA_TYPECLASS_BOILERPLATE(::Logical) -}} - // Difficulties: // 1. eval_if(false_, ...) will use Logical because it will try // to eval(false_), which is false_(), which is false. @@ -36,9 +31,9 @@ namespace boost { namespace hana { // Warning: make sure the whole approach with `eval` is not // fundamentally broken. There seems to be some loss of information // in eval(), which I suspect breaks the whole thing in subtle cases. -struct Logical : hana::typeclass { +struct Logical { + BOOST_HANA_TYPECLASS(Logical); struct mcd; - struct default_; }; BOOST_HANA_CONSTEXPR_LAMBDA auto if_ = [](auto logical, auto then_, auto else_) { @@ -83,17 +78,20 @@ struct Logical::mcd { { return eval_if(c, hana::always(t), hana::always(e)); } }; -struct Logical::default_ : Logical::mcd { - template - static constexpr auto eval_if_impl(Cond c, Then t, Else e) { - auto would_recurse = hana::decltype_(eval(c)) == hana::decltype_(c); - static_assert(!would_recurse(), - "Condition is probably not a logical. Trying to evaluate " - "it and use it as the condition to if_ again would cause " - "infinite recursion."); - return eval_if(eval(c), t, e); - } -}; +namespace boost { namespace hana { + template <> + struct default_instance< ::Logical> : ::Logical::mcd { + template + static constexpr auto eval_if_impl(Cond c, Then t, Else e) { + auto would_recurse = hana::decltype_(::eval(c)) == hana::decltype_(c); + static_assert(!would_recurse(), + "Condition is probably not a logical. Trying to evaluate " + "it and use it as the condition to if_ again would cause " + "infinite recursion."); + return ::eval_if(::eval(c), t, e); + } + }; +}} template <> struct Logical::instance : Logical::mcd {