2
0
mirror of https://github.com/boostorg/hana.git synced 2026-02-22 03:22:21 +00:00

Typeclasses: move provided instances for non-builtin types out of the forward decls.

This commit is contained in:
Louis Dionne
2014-07-23 16:13:40 -04:00
parent 1eca5548d8
commit 83dca441bb
6 changed files with 319 additions and 328 deletions

View File

@@ -10,19 +10,9 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef BOOST_HANA_LIST_LIST_HPP
#define BOOST_HANA_LIST_LIST_HPP
#include <boost/hana/applicative/mcd.hpp>
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates and convert
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/detail/std/type_traits.hpp>
#include <boost/hana/foldable/foldable.hpp>
#include <boost/hana/functor/fmap_mcd.hpp>
#include <boost/hana/iterable/iterable.hpp>
#include <boost/hana/logical/logical.hpp>
#include <boost/hana/maybe.hpp>
#include <boost/hana/monad/flatten_mcd.hpp>
#include <boost/hana/searchable/find_mcd.hpp>
#include <boost/hana/traversable/traverse_mcd.hpp>
#include <boost/hana/detail/typeclasses.hpp>
namespace boost { namespace hana {
@@ -361,159 +351,6 @@ namespace boost { namespace hana {
datatype_t<decltype(xs)>
>::zip_with_impl(f, xs, ys...);
};
//! @details
//! `List`s implement `fmap` as the mapping of a function over each
//! element of the list. This is somewhat equivalent to `std::transform`.
//! Mapping a function over an empty list returns an empty list and never
//! applies the function.
//!
//! ### Example 1
//! @snippet example/list/functor/fmap.cpp main
//!
//! ### Example 2
//! @snippet example/type_list/functor/fmap.cpp main
template <typename T>
struct Functor::instance<T, when<instantiates<List, T>()>>
: Functor::fmap_mcd
{
template <typename F, typename Xs>
static constexpr auto fmap_impl(F f, Xs xs) {
auto cons_f = [=](auto x, auto xs) { return cons(f(x), xs); };
return foldr(cons_f, nil<T>, xs);
}
};
//! @details
//! A value can be lifted into a singleton list with `lift`. `ap(fs, xs)`
//! applies each function in the list `fs` to each value in the list `xs`,
//! and returns a list containing all the results.
//!
//! ### Example
//! @snippet example/list/applicative/overview.cpp main
template <typename T>
struct Applicative::instance<T, when<instantiates<List, T>()>>
: Applicative::mcd
{
template <typename X>
static constexpr auto lift_impl(X x)
{ return cons(x, nil<T>); }
template <typename Fs, typename Xs>
static constexpr auto ap_impl(Fs fs, Xs xs)
{ return bind(fs, [=](auto f) { return fmap(f, xs); }); }
};
//! @details
//! A function returning a list of results can be mapped over all the
//! elements of a list and have all the results concatenated using `bind`.
//! Also, a list of lists can be flattened one level with `flatten`.
//!
//! ### Example
//! @snippet example/list/monad/overview.cpp main
template <typename T>
struct Monad::instance<T, when<instantiates<List, T>()>>
: Monad::flatten_mcd
{
template <typename Xss>
static constexpr auto flatten_impl(Xss xss)
{ return foldl(concat, nil<T>, xss); }
};
//! @details
//! This instance is hard to describe in words; see the examples.
//!
//! ### Example
//! @snippet example/list/traversable/traverse.cpp main
//!
//! ### Example
//! @snippet example/list/traversable/sequence.cpp main
template <typename T>
struct Traversable::instance<T, when<instantiates<List, T>()>>
: Traversable::traverse_mcd
{
template <typename A, typename F, typename Xs>
static constexpr auto traverse_impl(F f, Xs xs) {
auto curried_cons = [](auto x) {
return [=](auto xs) { return cons(x, xs); };
};
auto cons_f = [=](auto x, auto ys) {
return ap(fmap(curried_cons, f(x)), ys);
};
return foldr(cons_f, lift<A>(nil<T>), xs);
}
};
//! @details
//! Two `List`s are equal if and only if they contain the same number
//! of elements and their elements at any given index are equal.
//!
//! ### Example
//! @snippet example/list/comparable.cpp main
template <typename T, typename U>
struct Comparable::instance<T, U, when<
instantiates<List, T>() && instantiates<List, U>()
>> : Comparable::equal_mcd
{
template <typename Xs, typename Ys>
static constexpr auto equal_impl(Xs xs, Ys ys) {
return eval_if(or_(is_empty(xs), is_empty(ys)),
[=](auto _) {
return and_(_(is_empty)(xs), _(is_empty)(ys));
},
[=](auto _) {
return and_(equal(_(head)(xs), _(head)(ys)),
equal_impl(_(tail)(xs), _(tail)(ys)));
}
);
}
};
//! @details
//! A `List` can be searched by doing a linear search in the elements,
//! with the keys and values being both the elements in the list.
//!
//! @todo
//! Technically, this can be implemented in `Iterable`. Should it?
//!
//! ### Example
//! @snippet example/list/searchable/find.cpp main
template <typename T>
struct Searchable::instance<T, when<instantiates<List, T>()>>
: Searchable::find_mcd
{
template <typename Pred, typename Xs>
static constexpr auto find_impl(Pred pred, Xs xs) {
auto e = drop_until(pred, xs);
return eval_if(is_empty(e),
[](auto) { return nothing; },
[=](auto _) { return just(_(head)(e)); }
);
}
template <typename Pred, typename Xs>
static constexpr auto any_impl(Pred pred, Xs xs) {
return eval_if(is_empty(xs),
[](auto _) { return false_; },
[=](auto _) {
return eval_if(pred(_(head)(xs)),
[=](auto _) { return true_; },
[=](auto _) { return any_impl(pred, _(tail)(xs)); }
);
}
);
}
};
//! Converts a `Foldable` to a `List`.
template <typename L, typename T>
struct convert<L, T, detail::std::enable_if_t<
instantiates<List, L>() && instantiates<Foldable, T>()
>> {
template <typename Xs>
static constexpr auto apply(Xs xs)
{ return foldr(cons, nil<L>, xs); }
};
}} // end namespace boost::hana
#endif // !BOOST_HANA_LIST_LIST_HPP

View File

@@ -12,16 +12,21 @@ Distributed under the Boost Software License, Version 1.0.
#include <boost/hana/list/list.hpp>
#include <boost/hana/applicative/applicative.hpp>
#include <boost/hana/applicative/mcd.hpp>
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates and convert
#include <boost/hana/detail/right_folds/variadic_unrolled.hpp>
#include <boost/hana/foldable/foldable.hpp>
#include <boost/hana/functor/functor.hpp>
#include <boost/hana/functor/fmap_mcd.hpp>
#include <boost/hana/integral.hpp>
#include <boost/hana/iterable/iterable.hpp>
#include <boost/hana/logical/logical.hpp>
#include <boost/hana/monad/monad.hpp>
#include <boost/hana/maybe.hpp>
#include <boost/hana/monad/flatten_mcd.hpp>
#include <boost/hana/orderable/orderable.hpp>
#include <boost/hana/pair/instance.hpp>
#include <boost/hana/searchable/find_mcd.hpp>
#include <boost/hana/traversable/traverse_mcd.hpp>
namespace boost { namespace hana {
@@ -231,6 +236,159 @@ namespace boost { namespace hana {
);
}
};
//! @details
//! `List`s implement `fmap` as the mapping of a function over each
//! element of the list. This is somewhat equivalent to `std::transform`.
//! Mapping a function over an empty list returns an empty list and never
//! applies the function.
//!
//! ### Example 1
//! @snippet example/list/functor/fmap.cpp main
//!
//! ### Example 2
//! @snippet example/type_list/functor/fmap.cpp main
template <typename T>
struct Functor::instance<T, when<instantiates<List, T>()>>
: Functor::fmap_mcd
{
template <typename F, typename Xs>
static constexpr auto fmap_impl(F f, Xs xs) {
auto cons_f = [=](auto x, auto xs) { return cons(f(x), xs); };
return foldr(cons_f, nil<T>, xs);
}
};
//! @details
//! A value can be lifted into a singleton list with `lift`. `ap(fs, xs)`
//! applies each function in the list `fs` to each value in the list `xs`,
//! and returns a list containing all the results.
//!
//! ### Example
//! @snippet example/list/applicative/overview.cpp main
template <typename T>
struct Applicative::instance<T, when<instantiates<List, T>()>>
: Applicative::mcd
{
template <typename X>
static constexpr auto lift_impl(X x)
{ return cons(x, nil<T>); }
template <typename Fs, typename Xs>
static constexpr auto ap_impl(Fs fs, Xs xs)
{ return bind(fs, [=](auto f) { return fmap(f, xs); }); }
};
//! @details
//! A function returning a list of results can be mapped over all the
//! elements of a list and have all the results concatenated using `bind`.
//! Also, a list of lists can be flattened one level with `flatten`.
//!
//! ### Example
//! @snippet example/list/monad/overview.cpp main
template <typename T>
struct Monad::instance<T, when<instantiates<List, T>()>>
: Monad::flatten_mcd
{
template <typename Xss>
static constexpr auto flatten_impl(Xss xss)
{ return foldl(concat, nil<T>, xss); }
};
//! @details
//! This instance is hard to describe in words; see the examples.
//!
//! ### Example
//! @snippet example/list/traversable/traverse.cpp main
//!
//! ### Example
//! @snippet example/list/traversable/sequence.cpp main
template <typename T>
struct Traversable::instance<T, when<instantiates<List, T>()>>
: Traversable::traverse_mcd
{
template <typename A, typename F, typename Xs>
static constexpr auto traverse_impl(F f, Xs xs) {
auto curried_cons = [](auto x) {
return [=](auto xs) { return cons(x, xs); };
};
auto cons_f = [=](auto x, auto ys) {
return ap(fmap(curried_cons, f(x)), ys);
};
return foldr(cons_f, lift<A>(nil<T>), xs);
}
};
//! @details
//! Two `List`s are equal if and only if they contain the same number
//! of elements and their elements at any given index are equal.
//!
//! ### Example
//! @snippet example/list/comparable.cpp main
template <typename T, typename U>
struct Comparable::instance<T, U, when<
instantiates<List, T>() && instantiates<List, U>()
>> : Comparable::equal_mcd
{
template <typename Xs, typename Ys>
static constexpr auto equal_impl(Xs xs, Ys ys) {
return eval_if(or_(is_empty(xs), is_empty(ys)),
[=](auto _) {
return and_(_(is_empty)(xs), _(is_empty)(ys));
},
[=](auto _) {
return and_(equal(_(head)(xs), _(head)(ys)),
equal_impl(_(tail)(xs), _(tail)(ys)));
}
);
}
};
//! @details
//! A `List` can be searched by doing a linear search in the elements,
//! with the keys and values being both the elements in the list.
//!
//! @todo
//! Technically, this can be implemented in `Iterable`. Should it?
//!
//! ### Example
//! @snippet example/list/searchable/find.cpp main
template <typename T>
struct Searchable::instance<T, when<instantiates<List, T>()>>
: Searchable::find_mcd
{
template <typename Pred, typename Xs>
static constexpr auto find_impl(Pred pred, Xs xs) {
auto e = drop_until(pred, xs);
return eval_if(is_empty(e),
[](auto) { return nothing; },
[=](auto _) { return just(_(head)(e)); }
);
}
template <typename Pred, typename Xs>
static constexpr auto any_impl(Pred pred, Xs xs) {
return eval_if(is_empty(xs),
[](auto _) { return false_; },
[=](auto _) {
return eval_if(pred(_(head)(xs)),
[=](auto _) { return true_; },
[=](auto _) { return any_impl(pred, _(tail)(xs)); }
);
}
);
}
};
//! Converts a `Foldable` to a `List`.
template <typename L, typename T>
struct convert<L, T, detail::std::enable_if_t<
instantiates<List, L>() && instantiates<Foldable, T>()
>> {
template <typename Xs>
static constexpr auto apply(Xs xs)
{ return foldr(cons, nil<L>, xs); }
};
}} // end namespace boost::hana
#endif // !BOOST_HANA_LIST_MCD_HPP

View File

@@ -12,10 +12,88 @@ Distributed under the Boost Software License, Version 1.0.
#include <boost/hana/pair/pair.hpp>
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates
#include <boost/hana/logical/logical.hpp>
namespace boost { namespace hana {
//! Minimal complete definition: `first` and `second`
struct Pair::mcd { };
//! @details
//! Two pairs `x` and `y` are equal iff they are equal element-wise,
//! i.e. iff
//! @code
//! first(x) == first(y) && second(x) == second(y)
//! @endcode
//!
//! ### Example
//! @snippet example/pair/comparable.cpp main
template <typename T, typename U>
struct Comparable::instance<T, U, when<
instantiates<Pair, T>() && instantiates<Pair, U>()
>> : Comparable::equal_mcd {
template <typename X, typename Y>
static constexpr auto equal_impl(X x, Y y) {
return and_(
equal(first(x), first(y)),
equal(second(x), second(y))
);
}
};
#if 0
template <typename T>
struct Functor::instance<T, when<instantiates<Pair, T>()>>
: Functor::fmap_mcd
{
template <typename F, typename P>
static constexpr auto fmap_impl(F f, P p)
{ return pair(f(first(p)), f(second(p))); }
};
template <typename T>
struct Applicative::instance<T, when<instantiates<Pair, T>()>>
: Applicative::mcd
{
template <typename X>
static constexpr auto lift_impl(X x)
{ return pair(x, x); }
template <typename F, typename P>
static constexpr auto ap_impl(F f, P p)
{ return pair(first(f)(first(p), second(f)(second(p)))); }
};
template <typename T>
struct Monad::instance<T, when<instantiates<Pair, T>()>>
: Monad::bind_mcd
{
template <typename P, typename F>
static constexpr auto bind_impl(P p, F f) {
return pair(
bind(first(p), compose(first, f)),
bind(second(p), compose(second, f))
);
}
};
template <typename T>
struct Foldable::instance<T, when<instantiates<Pair, T>()>>
: Foldable::mcd
{
template <typename F, typename S, typename P>
static constexpr auto foldr_impl(F f, S s, P p) {
return f(first(p), f(second(p), s));
}
template <typename F, typename S, typename P>
static constexpr auto foldl_impl(F f, S s, P p) {
return f(f(s, first(p)), second(p));
}
};
#endif
}} // end namespace boost::hana
#endif // !BOOST_HANA_PAIR_MCD_HPP

View File

@@ -10,10 +10,8 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef BOOST_HANA_PAIR_PAIR_HPP
#define BOOST_HANA_PAIR_PAIR_HPP
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/logical/logical.hpp>
#include <boost/hana/detail/typeclasses.hpp>
namespace boost { namespace hana {
@@ -56,80 +54,6 @@ namespace boost { namespace hana {
datatype_t<decltype(pair)>
>::second_impl(pair);
};
//! @details
//! Two pairs `x` and `y` are equal iff they are equal element-wise,
//! i.e. iff
//! @code
//! first(x) == first(y) && second(x) == second(y)
//! @endcode
//!
//! ### Example
//! @snippet example/pair/comparable.cpp main
template <typename T, typename U>
struct Comparable::instance<T, U, when<
instantiates<Pair, T>() && instantiates<Pair, U>()
>> : Comparable::equal_mcd {
template <typename X, typename Y>
static constexpr auto equal_impl(X x, Y y) {
return and_(
equal(first(x), first(y)),
equal(second(x), second(y))
);
}
};
#if 0
template <typename T>
struct Functor::instance<T, when<instantiates<Pair, T>()>>
: Functor::fmap_mcd
{
template <typename F, typename P>
static constexpr auto fmap_impl(F f, P p)
{ return pair(f(first(p)), f(second(p))); }
};
template <typename T>
struct Applicative::instance<T, when<instantiates<Pair, T>()>>
: Applicative::mcd
{
template <typename X>
static constexpr auto lift_impl(X x)
{ return pair(x, x); }
template <typename F, typename P>
static constexpr auto ap_impl(F f, P p)
{ return pair(first(f)(first(p), second(f)(second(p)))); }
};
template <typename T>
struct Monad::instance<T, when<instantiates<Pair, T>()>>
: Monad::bind_mcd
{
template <typename P, typename F>
static constexpr auto bind_impl(P p, F f) {
return pair(
bind(first(p), compose(first, f)),
bind(second(p), compose(second, f))
);
}
};
template <typename T>
struct Foldable::instance<T, when<instantiates<Pair, T>()>>
: Foldable::mcd
{
template <typename F, typename S, typename P>
static constexpr auto foldr_impl(F f, S s, P p) {
return f(first(p), f(second(p), s));
}
template <typename F, typename S, typename P>
static constexpr auto foldl_impl(F f, S s, P p) {
return f(f(s, first(p)), second(p));
}
};
#endif
}} // end namespace boost::hana
#endif // !BOOST_HANA_PAIR_PAIR_HPP

View File

@@ -12,11 +12,88 @@ Distributed under the Boost Software License, Version 1.0.
#include <boost/hana/record/record.hpp>
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates
#include <boost/hana/detail/std/type_traits.hpp>
#include <boost/hana/foldable/mcd.hpp>
#include <boost/hana/map.hpp>
#include <boost/hana/pair/instance.hpp>
#include <boost/hana/searchable/find_mcd.hpp>
namespace boost { namespace hana {
//! Minimal complete definition: `members`
struct Record::mcd {
struct Record::mcd { };
//! Two `Records` of the same data type `R` are equal if and only if
//! all their members are equal. The members are compared in the
//! same order as they appear in `members<R>`.
template <typename R>
struct Comparable::instance<R, R, when<instantiates<Record, R>()>>
: Comparable::equal_mcd
{
template <typename X, typename Y>
static constexpr auto equal_impl(X x, Y y) {
return all([=](auto k_f) {
return equal(second(k_f)(x), second(k_f)(y));
}, members<R>);
}
};
//! Folding a `Record` `R` is equivalent to folding a list of its members,
//! in the same order as they appear in `members<R>`.
template <typename R>
struct Foldable::instance<R, when<instantiates<Record, R>()>>
: Foldable::mcd
{
template <typename F, typename S, typename X>
static constexpr auto foldl_impl(F f, S s, X x) {
auto g = [=](auto s, auto k_f) {
return f(s, second(k_f)(x));
};
return foldl(g, s, members<R>);
}
template <typename F, typename S, typename X>
static constexpr auto foldr_impl(F f, S s, X x) {
auto g = [=](auto k_f, auto s) {
return f(second(k_f)(x), s);
};
return foldr(g, s, members<R>);
}
};
//! Searching a `Record` `r` is equivalent to searching `to<Map>(r)`.
template <typename R>
struct Searchable::instance<R, when<instantiates<Record, R>()>>
: Searchable::find_mcd
{
template <typename Pred, typename X>
static constexpr auto find_impl(Pred pred, X x) {
return fmap(
[=](auto k_f) { return second(k_f)(x); },
find([=](auto k_f) { return pred(first(k_f)); }, members<R>)
);
}
template <typename Pred, typename X>
static constexpr auto any_impl(Pred pred, X x) {
return any([=](auto k_f) { return pred(first(k_f)); }, members<R>);
}
};
//! Converting a `Record` `R` to a `Map` is equivalent to converting its
//! `members<R>` to a `Map`, except the values are replaced by the actual
//! members of the object instead of accessors.
template <typename R>
struct convert<Map, R, detail::std::enable_if_t<instantiates<Record, R>()>> {
template <typename X>
static constexpr auto apply(X x) {
return to<Map>(fmap(
[=](auto k_f) { return pair(first(k_f), second(k_f)(x)); },
members<R>
));
}
};
}} // end namespace boost::hana

View File

@@ -40,87 +40,4 @@ namespace boost { namespace hana {
BOOST_HANA_CONSTEXPR_LAMBDA auto members = Record::instance<R>::members_impl();
}} // end namespace boost::hana
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/core.hpp> // for instantiates
#include <boost/hana/detail/std/type_traits.hpp>
#include <boost/hana/foldable/mcd.hpp>
#include <boost/hana/map.hpp>
#include <boost/hana/pair/instance.hpp>
#include <boost/hana/searchable/find_mcd.hpp>
namespace boost { namespace hana {
//! Two `Records` of the same data type `R` are equal if and only if
//! all their members are equal. The members are compared in the
//! same order as they appear in `members<R>`.
template <typename R>
struct Comparable::instance<R, R, when<instantiates<Record, R>()>>
: Comparable::equal_mcd
{
template <typename X, typename Y>
static constexpr auto equal_impl(X x, Y y) {
return all([=](auto k_f) {
return equal(second(k_f)(x), second(k_f)(y));
}, members<R>);
}
};
//! Folding a `Record` `R` is equivalent to folding a list of its members,
//! in the same order as they appear in `members<R>`.
template <typename R>
struct Foldable::instance<R, when<instantiates<Record, R>()>>
: Foldable::mcd
{
template <typename F, typename S, typename X>
static constexpr auto foldl_impl(F f, S s, X x) {
auto g = [=](auto s, auto k_f) {
return f(s, second(k_f)(x));
};
return foldl(g, s, members<R>);
}
template <typename F, typename S, typename X>
static constexpr auto foldr_impl(F f, S s, X x) {
auto g = [=](auto k_f, auto s) {
return f(second(k_f)(x), s);
};
return foldr(g, s, members<R>);
}
};
//! Searching a `Record` `r` is equivalent to searching `to<Map>(r)`.
template <typename R>
struct Searchable::instance<R, when<instantiates<Record, R>()>>
: Searchable::find_mcd
{
template <typename Pred, typename X>
static constexpr auto find_impl(Pred pred, X x) {
return fmap(
[=](auto k_f) { return second(k_f)(x); },
find([=](auto k_f) { return pred(first(k_f)); }, members<R>)
);
}
template <typename Pred, typename X>
static constexpr auto any_impl(Pred pred, X x) {
return any([=](auto k_f) { return pred(first(k_f)); }, members<R>);
}
};
//! Converting a `Record` `R` to a `Map` is equivalent to converting its
//! `members<R>` to a `Map`, except the values are replaced by the actual
//! members of the object instead of accessors.
template <typename R>
struct convert<Map, R, detail::std::enable_if_t<instantiates<Record, R>()>> {
template <typename X>
static constexpr auto apply(X x) {
return to<Map>(fmap(
[=](auto k_f) { return pair(first(k_f), second(k_f)(x)); },
members<R>
));
}
};
}} // end namespace boost::hana
#endif // !BOOST_HANA_RECORD_RECORD_HPP