stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,117 @@
/*!
@file
Forward declares `boost::hana::Applicative`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_APPLICATIVE_HPP
#define BOOST_HANA_FWD_CONCEPT_APPLICATIVE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Applicative Applicative
//! The `Applicative` concept represents `Functor`s with the ability
//! to lift values and combine computations.
//!
//! A `Functor` can only take a normal function and map it over a
//! structure containing values to obtain a new structure containing
//! values. Intuitively, an `Applicative` can also take a value and
//! lift it into the structure. In addition, an `Applicative` can take
//! a structure containing functions and apply it to a structure
//! containing values to obtain a new structure containing values.
//! By currying the function(s) inside the structure, it is then
//! also possible to apply n-ary functions to n structures containing
//! values.
//!
//! @note
//! This documentation does not go into much details about the nature
//! of applicatives. However, the [Typeclassopedia][1] is a nice
//! Haskell-oriented resource where such information can be found.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `lift` and `ap` satisfying the laws below. An `Applicative` must
//! also be a `Functor`.
//!
//!
//! Laws
//! ----
//! Given an `Applicative` `F`, the following laws must be satisfied:
//! 1. Identity\n
//! For all objects `xs` of tag `F(A)`,
//! @code
//! ap(lift<F>(id), xs) == xs
//! @endcode
//!
//! 2. Composition\n
//! For all objects `xs` of tag `F(A)` and functions-in-an-applicative
//! @f$ fs : F(B \to C) @f$,
//! @f$ gs : F(A \to B) @f$,
//! @code
//! ap(ap(lift<F>(compose), fs, gs), xs) == ap(fs, ap(gs, xs))
//! @endcode
//!
//! 3. Homomorphism\n
//! For all objects `x` of tag `A` and functions @f$ f : A \to B @f$,
//! @code
//! ap(lift<F>(f), lift<F>(x)) == lift<F>(f(x))
//! @endcode
//!
//! 4. Interchange\n
//! For all objects `x` of tag `A` and functions-in-an-applicative
//! @f$ fs : F(A \to B) @f$,
//! @code
//! ap(fs, lift<F>(x)) == ap(lift<F>(apply(-, x)), fs)
//! @endcode
//! where `apply(-, x)` denotes the partial application of the `apply`
//! function from the @ref group-functional module to the `x` argument.
//!
//! As a consequence of these laws, the model of `Functor` for `F` will
//! satisfy the following for all objects `xs` of tag `F(A)` and functions
//! @f$ f : A \to B @f$:
//! @code
//! transform(xs, f) == ap(lift<F>(f), xs)
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Functor` (free model)\n
//! As a consequence of the laws, any `Applicative F` can be made a
//! `Functor` by setting
//! @code
//! transform(xs, f) = ap(lift<F>(f), xs)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! @anchor applicative-transformation
//! Structure-preserving functions
//! ------------------------------
//! An _applicative transformation_ is a function @f$ t : F(X) \to G(X) @f$
//! between two Applicatives `F` and `G`, where `X` can be any tag, and
//! which preserves the operations of an Applicative. In other words, for
//! all objects `x` of tag `X`, functions-in-an-applicative
//! @f$ fs : F(X \to Y) @f$ and objects `xs` of tag `F(X)`,
//! @code
//! t(lift<F>(x)) == lift<G>(x)
//! t(ap(fs, xs)) == ap(t(fs), t(xs))
//! @endcode
//!
//! [1]: https://wiki.haskell.org/Typeclassopedia#Applicative
template <typename A>
struct Applicative;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_APPLICATIVE_HPP
@@ -0,0 +1,111 @@
/*!
@file
Forward declares `boost::hana::Comonad`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_COMONAD_HPP
#define BOOST_HANA_FWD_CONCEPT_COMONAD_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note: We use a multiline C++ comment because there's a double backslash
// symbol in the documentation (for LaTeX), which triggers
// warning: multi-line comment [-Wcomment]
// on GCC.
/*!
@ingroup group-concepts
@defgroup group-Comonad Comonad
The `Comonad` concept represents context-sensitive computations and
data.
Formally, the Comonad concept is dual to the Monad concept.
But unless you're a mathematician, you don't care about that and it's
fine. So intuitively, a Comonad represents context sensitive values
and computations. First, Comonads make it possible to extract
context-sensitive values from their context with `extract`.
In contrast, Monads make it possible to wrap raw values into
a given context with `lift` (from Applicative).
Secondly, Comonads make it possible to apply context-sensitive values
to functions accepting those, and to return the result as a
context-sensitive value using `extend`. In contrast, Monads make
it possible to apply a monadic value to a function accepting a normal
value and returning a monadic value, and to return the result as a
monadic value (with `chain`).
Finally, Comonads make it possible to wrap a context-sensitive value
into an extra layer of context using `duplicate`, while Monads make
it possible to take a value with an extra layer of context and to
strip it with `flatten`.
Whereas `lift`, `chain` and `flatten` from Applicative and Monad have
signatures
\f{align*}{
\mathtt{lift}_M &: T \to M(T) \\
\mathtt{chain} &: M(T) \times (T \to M(U)) \to M(U) \\
\mathtt{flatten} &: M(M(T)) \to M(T)
\f}
`extract`, `extend` and `duplicate` from Comonad have signatures
\f{align*}{
\mathtt{extract} &: W(T) \to T \\
\mathtt{extend} &: W(T) \times (W(T) \to U) \to W(U) \\
\mathtt{duplicate} &: W(T) \to W(W(T))
\f}
Notice how the "arrows" are reversed. This symmetry is essentially
what we mean by Comonad being the _dual_ of Monad.
@note
The [Typeclassopedia][1] is a nice Haskell-oriented resource for further
reading about Comonads.
Minimal complete definition
---------------------------
`extract` and (`extend` or `duplicate`) satisfying the laws below.
A `Comonad` must also be a `Functor`.
Laws
----
For all Comonads `w`, the following laws must be satisfied:
@code
extract(duplicate(w)) == w
transform(duplicate(w), extract) == w
duplicate(duplicate(w)) == transform(duplicate(w), duplicate)
@endcode
@note
There are several equivalent ways of defining Comonads, and this one
is just one that was picked arbitrarily for simplicity.
Refined concept
---------------
1. Functor\n
Every Comonad is also required to be a Functor. At first, one might think
that it should instead be some imaginary concept CoFunctor. However, it
turns out that a CoFunctor is the same as a `Functor`, hence the
requirement that a `Comonad` also is a `Functor`.
Concrete models
---------------
`hana::lazy`
[1]: https://wiki.haskell.org/Typeclassopedia#Comonad
*/
template <typename W>
struct Comonad;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_COMONAD_HPP
@@ -0,0 +1,160 @@
/*!
@file
Forward declares `boost::hana::Comparable`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_COMPARABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_COMPARABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Comparable Comparable
//! The `Comparable` concept defines equality and inequality.
//!
//! Intuitively, `Comparable` objects must define a binary predicate named
//! `equal` that returns whether both objects represent the same abstract
//! value. In other words, `equal` must check for deep equality. Since
//! "representing the same abstract value" is difficult to express
//! formally, the exact meaning of equality is partially left to
//! interpretation by the programmer with the following guidelines:\n
//! 1. Equality should be compatible with copy construction; copy
//! constructing a value yields an `equal` value.
//! 2. Equality should be independent of representation; an object
//! representing a fraction as `4/8` should be `equal` to an object
//! representing a fraction as `2/4`, because they both represent
//! the mathematical object `1/2`.
//!
//! Moreover, `equal` must exhibit properties that make it intuitive to
//! use for determining the equivalence of objects, which is formalized
//! by the laws for `Comparable`.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! 1. `equal`\n
//! When `equal` is defined, `not_equal` is implemented by default as its
//! complement. For all objects `x`, `y` of a `Comparable` tag,
//! @code
//! not_equal(x, y) == not_(equal(x, y))
//! @endcode
//!
//!
//! Laws
//! ----
//! `equal` must define an [equivalence relation][1], and `not_equal` must
//! be its complement. In other words, for all objects `a`, `b`, `c` with
//! a `Comparable` tag, the following must hold:
//! @code
//! equal(a, a) // Reflexivity
//! if equal(a, b) then equal(b, a) // Symmetry
//! if equal(a, b) && equal(b, c) then equal(a, c) // Transitivity
//! not_equal(a, b) is equivalent to not_(equal(a, b))
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::map`, `hana::optional`, `hana::pair`,
//! `hana::range`, `hana::set`, `hana::string`, `hana::tuple`,
//! `hana::type`
//!
//!
//! Free model for `EqualityComparable` data types
//! ----------------------------------------------
//! Two data types `T` and `U` that model the cross-type EqualityComparable
//! concept presented in [N3351][2] automatically model the `Comparable`
//! concept by setting
//! @code
//! equal(x, y) = (x == y)
//! @endcode
//! Note that this also makes EqualityComparable types in the
//! [usual sense][3] models of `Comparable` in the same way.
//!
//!
//! Equality-preserving functions
//! -----------------------------
//! Let `A` and `B` be two `Comparable` tags. A function @f$f : A \to B@f$
//! is said to be equality-preserving if it preserves the structure of the
//! `Comparable` concept, which can be rigorously stated as follows. For
//! all objects `x`, `y` of tag `A`,
//! @code
//! if equal(x, y) then equal(f(x), f(y))
//! @endcode
//! Equivalently, we simply require that `f` is a function in the usual
//! mathematical sense. Another property is [injectivity][4], which can be
//! viewed as being a "lossless" mapping. This property can be stated as
//! @code
//! if equal(f(x), f(y)) then equal(x, y)
//! @endcode
//! This is equivalent to saying that `f` maps distinct elements to
//! distinct elements, hence the "lossless" analogy. In other words, `f`
//! will not collapse distinct elements from its domain into a single
//! element in its image, thus losing information.
//!
//! These functions are very important, especially equality-preserving
//! ones, because they allow us to reason simply about programs. Also
//! note that the property of being equality-preserving is taken for
//! granted in mathematics because it is part of the definition of a
//! function. We feel it is important to make the distinction here
//! because programming has evolved differently and as a result
//! programmers are used to work with functions that do not preserve
//! equality.
//!
//!
//! Cross-type version of the methods
//! ---------------------------------
//! The `equal` and `not_equal` methods are "overloaded" to handle
//! distinct tags with certain properties. Specifically, they are
//! defined for _distinct_ tags `A` and `B` such that
//! 1. `A` and `B` share a common tag `C`, as determined by the
//! `common` metafunction
//! 2. `A`, `B` and `C` are all `Comparable` when taken individually
//! 3. @f$ \mathtt{to<C>} : A \to C @f$ and @f$\mathtt{to<C>} : B \to C@f$
//! are both equality-preserving and injective (i.e. they are embeddings),
//! as determined by the `is_embedding` metafunction.
//!
//! The method definitions for tags satisfying the above properties are
//! @code
//! equal(x, y) = equal(to<C>(x), to<C>(y))
//! not_equal(x, y) = not_equal(to<C>(x), to<C>(y))
//! @endcode
//!
//!
//! Important note: special behavior of `equal`
//! -------------------------------------------
//! In the context of programming with heterogeneous values, it is useful
//! to have unrelated objects compare `false` instead of triggering an
//! error. For this reason, `equal` adopts a special behavior for
//! unrelated objects of tags `T` and `U` that do not satisfy the above
//! requirements for the cross-type overloads. Specifically, when `T` and
//! `U` are unrelated (i.e. `T` can't be converted to `U` and vice-versa),
//! comparing objects with those tags yields a compile-time false value.
//! This has the effect that unrelated objects like `float` and
//! `std::string` will compare false, while comparing related objects that
//! can not be safely embedded into the same super structure (like
//! `long long` and `float` because of the precision loss) will trigger a
//! compile-time assertion. Also note that for any tag `T` for which the
//! minimal complete definition of `Comparable` is not provided, a
//! compile-time assertion will also be triggered because `T` and `T`
//! trivially share the common tag `T`, which is the expected behavior.
//! This design choice aims to provide more flexibility for comparing
//! objects, while still rejecting usage patterns that are most likely
//! programming errors.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Equivalence_relation#Definition
//! [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
//! [3]: http://en.cppreference.com/w/cpp/concept/EqualityComparable
//! [4]: http://en.wikipedia.org/wiki/Injective_function
template <typename T>
struct Comparable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_COMPARABLE_HPP
@@ -0,0 +1,210 @@
/*!
@file
Forward declares `boost::hana::Constant`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_CONSTANT_HPP
#define BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Constant Constant
//! The `Constant` concept represents data that can be manipulated at
//! compile-time.
//!
//! At its core, `Constant` is simply a generalization of the principle
//! behind `std::integral_constant` to all types that can be constructed
//! at compile-time, i.e. to all types with a `constexpr` constructor
//! (also called [Literal types][1]). More specifically, a `Constant` is
//! an object from which a `constexpr` value may be obtained (through the
//! `value` method) regardless of the `constexpr`ness of the object itself.
//!
//! All `Constant`s must be somewhat equivalent, in the following sense.
//! Let `C(T)` and `D(U)` denote the tags of `Constant`s holding objects
//! of type `T` and `U`, respectively. Then, an object with tag `D(U)`
//! must be convertible to an object with tag `C(T)` whenever `U` is
//! convertible to `T`, as determined by `is_convertible`. The
//! interpretation here is that a `Constant` is just a box holding
//! an object of some type, and it should be possible to swap between
//! boxes whenever the objects inside the boxes can be swapped.
//!
//! Because of this last requirement, one could be tempted to think that
//! specialized "boxes" like `std::integral_constant` are prevented from
//! being `Constant`s because they are not able to hold objects of any
//! type `T` (`std::integral_constant` may only hold integral types).
//! This is false; the requirement should be interpreted as saying that
//! whenever `C(T)` is _meaningful_ (e.g. only when `T` is integral for
//! `std::integral_constant`) _and_ there exists a conversion from `U`
//! to `T`, then a conversion from `D(U)` to `C(T)` should also exist.
//! The precise requirements for being a `Constant` are embodied in the
//! following laws.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `value` and `to`, satisfying the laws below.
//!
//!
//! Laws
//! ----
//! Let `c` be an object of with tag `C`, which represents a `Constant`
//! holding an object with tag `T`. The first law ensures that the value
//! of the wrapped object is always a constant expression by requiring
//! the following to be well-formed:
//! @code
//! constexpr auto x = hana::value<decltype(c)>();
//! @endcode
//!
//! This means that the `value` function must return an object that can
//! be constructed at compile-time. It is important to note how `value`
//! only receives the type of the object and not the object itself.
//! This is the core of the `Constant` concept; it means that the only
//! information required to implement `value` must be stored in the _type_
//! of its argument, and hence be available statically.
//!
//! The second law that must be satisfied ensures that `Constant`s are
//! basically dumb boxes, which makes it possible to provide models for
//! many concepts without much work from the user. The law simply asks
//! for the following expression to be valid:
//! @code
//! to<C>(i)
//! @endcode
//! where, `i` is an _arbitrary_ `Constant` holding an internal value
//! with a tag that can be converted to `T`, as determined by the
//! `hana::is_convertible` metafunction. In other words, whenever `U` is
//! convertible to `T`, a `Constant` holding a `U` is convertible to
//! a `Constant` holding a `T`, if such a `Constant` can be created.
//!
//! Finally, the tag `C` must provide a nested `value_type` alias to `T`,
//! which allows us to query the tag of the inner value held by objects
//! with tag `C`. In other words, the following must be true for any
//! object `c` with tag `C`:
//! @code
//! std::is_same<
//! C::value_type,
//! tag_of<decltype(hana::value(c))>::type
//! >::value
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! In certain cases, a `Constant` can automatically be made a model of
//! another concept. In particular, if a `Constant` `C` is holding an
//! object of tag `T`, and if `T` models a concept `X`, then `C` may
//! in most cases model `X` by simply performing whatever operation is
//! required on its underlying value, and then wrapping the result back
//! in a `C`.
//!
//! More specifically, if a `Constant` `C` has an underlying value
//! (`C::value_type`) which is a model of `Comparable`, `Orderable`,
//! `Logical`, or `Monoid` up to `EuclideanRing`, then `C` must also
//! be a model of those concepts. In other words, when `C::value_type`
//! models one of the listed concepts, `C` itself must also model that
//! concept. However, note that free models are provided for all of
//! those concepts, so no additional work must be done.
//!
//! While it would be possible in theory to provide models for concepts
//! like `Foldable` too, only a couple of concepts are useful to have as
//! `Constant` in practice. Providing free models for the concepts listed
//! above is useful because it allows various types of integral constants
//! (`std::integral_constant`, `mpl::integral_c`, etc...) to easily have
//! models for them just by defining the `Constant` concept.
//!
//! @remark
//! An interesting observation is that `Constant` is actually the
//! canonical embedding of the subcategory of `constexpr` things
//! into the Hana category, which contains everything in this library.
//! Hence, whatever is true in that subcategory is also true here, via
//! this functor. This is why we can provide models of any concept that
//! works on `constexpr` things for Constants, by simply passing them
//! through that embedding.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Provided conversion to the tag of the underlying value
//! ------------------------------------------------------
//! Any `Constant` `c` holding an underlying value of tag `T` is
//! convertible to any tag `U` such that `T` is convertible to `U`.
//! Specifically, the conversion is equivalent to
//! @code
//! to<U>(c) == to<U>(value<decltype(c)>())
//! @endcode
//!
//! Also, those conversions are marked as an embedding whenever the
//! conversion of underlying types is an embedding. This is to allow
//! Constants to inter-operate with `constexpr` objects easily:
//! @code
//! plus(int_c<1>, 1) == 2
//! @endcode
//!
//! Strictly speaking, __this is sometimes a violation__ of what it means
//! to be an embedding. Indeed, while there exists an embedding from any
//! Constant to a `constexpr` object (since Constant is just the canonical
//! inclusion), there is no embedding from a Constant to a runtime
//! object since we would lose the ability to define the `value` method
//! (the `constexpr`ness of the object would have been lost). Since there
//! is no way to distinguish `constexpr` and non-`constexpr` objects based
//! on their type, Hana has no way to know whether the conversion is to a
//! `constexpr` object of not. In other words, the `to` method has no way
//! to differentiate between
//! @code
//! constexpr int i = hana::to<int>(int_c<1>);
//! @endcode
//! which is an embedding, and
//! @code
//! int i = hana::to<int>(int_c<1>);
//! @endcode
//!
//! which isn't. To be on the safer side, we could mark the conversion
//! as not-an-embedding. However, if e.g. the conversion from
//! `integral_constant_tag<int>` to `int` was not marked as an embedding,
//! we would have to write `plus(to<int>(int_c<1>), 1)` instead of just
//! `plus(int_c<1>, 1)`, which is cumbersome. Hence, the conversion is
//! marked as an embedding, but this also means that code like
//! @code
//! int i = 1;
//! plus(int_c<1>, i);
//! @endcode
//! will be considered valid, which implicitly loses the fact that
//! `int_c<1>` is a Constant, and hence does not follow the usual rules
//! for cross-type operations in Hana.
//!
//!
//! Provided common data type
//! -------------------------
//! Because of the requirement that `Constant`s be interchangeable when
//! their contents are compatible, two `Constant`s `A` and `B` will have
//! a common data type whenever `A::value_type` and `B::value_type` have
//! one. Their common data type is an unspecified `Constant` `C` such
//! that `C::value_type` is exactly `common_t<A::value_type, B::value_type>`.
//! A specialization of the `common` metafunction is provided for
//! `Constant`s to reflect this.
//!
//! In the same vein, a common data type is also provided from any
//! constant `A` to a type `T` such that `A::value_type` and `T` share
//! a common type. The common type between `A` and `T` is obviously the
//! common type between `A::value_type` and `T`. As explained above in
//! the section on conversions, this is sometimes a violation of the
//! definition of a common type, because there must be an embedding
//! to the common type, which is not always the case. For the same
//! reasons as explained above, this common type is still provided.
//!
//!
//! [1]: http://en.cppreference.com/w/cpp/concept/LiteralType
template <typename C>
struct Constant;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP
@@ -0,0 +1,117 @@
/*!
@file
Forward declares `boost::hana::EuclideanRing`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_EUCLIDEAN_RING_HPP
#define BOOST_HANA_FWD_CONCEPT_EUCLIDEAN_RING_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-EuclideanRing Euclidean Ring
//! The `EuclideanRing` concept represents a commutative `Ring` that
//! can also be endowed with a division algorithm.
//!
//! A Ring defines a binary operation often called _multiplication_ that
//! can be used to combine two elements of the ring into a new element of
//! the ring. An [Euclidean ring][1], also called an Euclidean domain, adds
//! the ability to define a special function that generalizes the Euclidean
//! division of integers.
//!
//! However, an Euclidean ring must also satisfy one more property, which
//! is that of having no non-zero zero divisors. In a Ring `(R, +, *)`, it
//! follows quite easily from the axioms that `x * 0 == 0` for any ring
//! element `x`. However, there is nothing that mandates `0` to be the
//! only ring element sending other elements to `0`. Hence, in some Rings,
//! it is possible to have elements `x` and `y` such that `x * y == 0`
//! while not having `x == 0` nor `y == 0`. We call these elements divisors
//! of zero, or zero divisors. For example, this situation arises in the
//! Ring of integers modulo 4 (the set `{0, 1, 2, 3}`) with addition and
//! multiplication `mod 4` as binary operations. In this case, we have that
//! @code
//! 2 * 2 == 4
//! == 0 (mod 4)
//! @endcode
//! even though `2 != 0 (mod 4)`.
//!
//! Following this line of thought, an Euclidean ring requires its only
//! zero divisor is zero itself. In other words, the multiplication in an
//! Euclidean won't send two non-zero elements to zero. Also note that
//! since multiplication in a `Ring` is not necessarily commutative, it
//! is not always the case that
//! @code
//! x * y == 0 implies y * x == 0
//! @endcode
//! To be rigorous, we should then distinguish between elements that are
//! zero divisors when multiplied to the right and to the left.
//! Fortunately, the concept of an Euclidean ring requires the Ring
//! multiplication to be commutative. Hence,
//! @code
//! x * y == y * x
//! @endcode
//! and we do not have to distinguish between left and right zero divisors.
//!
//! Typical examples of Euclidean rings include integers and polynomials
//! over a field. The method names used here refer to the Euclidean ring
//! of integers under the usual addition, multiplication and division
//! operations.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `div` and `mod` satisfying the laws below
//!
//!
//! Laws
//! ----
//! To simplify the reading, we will use the `+`, `*`, `/` and `%`
//! operators with infix notation to denote the application of the
//! corresponding methods in Monoid, Group, Ring and EuclideanRing.
//! For all objects `a` and `b` of an `EuclideanRing` `R`, the
//! following laws must be satisfied:
//! @code
//! a * b == b * a // commutativity
//! (a / b) * b + a % b == a if b is non-zero
//! zero<R>() % b == zero<R>() if b is non-zero
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Monoid`, `Group`, `Ring`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean integral data types
//! ----------------------------------------------
//! A data type `T` is integral if `std::is_integral<T>::%value` is true.
//! For a non-boolean integral data type `T`, a model of `EuclideanRing`
//! is automatically defined by using the `Ring` model provided for
//! arithmetic data types and setting
//! @code
//! div(x, y) = (x / y)
//! mod(x, y) = (x % y)
//! @endcode
//!
//! @note
//! The rationale for not providing an EuclideanRing model for `bool` is
//! the same as for not providing Monoid, Group and Ring models.
//!
//!
//! [1]: https://en.wikipedia.org/wiki/Euclidean_domain
template <typename R>
struct EuclideanRing;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_EUCLIDEAN_RING_HPP
@@ -0,0 +1,141 @@
/*!
@file
Forward declares `boost::hana::Foldable`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_FOLDABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_FOLDABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Foldable Foldable
//! The `Foldable` concept represents data structures that can be reduced
//! to a single value.
//!
//! Generally speaking, folding refers to the concept of summarizing a
//! complex structure as a single value, by successively applying a
//! binary operation which reduces two elements of the structure to a
//! single value. Folds come in many flavors; left folds, right folds,
//! folds with and without an initial reduction state, and their monadic
//! variants. This concept is able to express all of these fold variants.
//!
//! Another way of seeing `Foldable` is as data structures supporting
//! internal iteration with the ability to accumulate a result. By
//! internal iteration, we mean that the _loop control_ is in the hand
//! of the structure, not the caller. Hence, it is the structure who
//! decides when the iteration stops, which is normally when the whole
//! structure has been consumed. Since C++ is an eager language, this
//! requires `Foldable` structures to be finite, or otherwise one would
//! need to loop indefinitely to consume the whole structure.
//!
//! @note
//! While the fact that `Foldable` only works for finite structures may
//! seem overly restrictive in comparison to the Haskell definition of
//! `Foldable`, a finer grained separation of the concepts should
//! mitigate the issue. For iterating over possibly infinite data
//! structures, see the `Iterable` concept. For searching a possibly
//! infinite data structure, see the `Searchable` concept.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `fold_left` or `unpack`
//!
//! However, please note that a minimal complete definition provided
//! through `unpack` will be much more compile-time efficient than one
//! provided through `fold_left`.
//!
//!
//! Concrete models
//! ---------------
//! `hana::map`, `hana::optional`, `hana::pair`, `hana::set`,
//! `hana::range`, `hana::tuple`
//!
//!
//! @anchor Foldable-lin
//! The linearization of a `Foldable`
//! ---------------------------------
//! Intuitively, for a `Foldable` structure `xs`, the _linearization_ of
//! `xs` is the sequence of all the elements in `xs` as if they had been
//! put in a list:
//! @code
//! linearization(xs) = [x1, x2, ..., xn]
//! @endcode
//!
//! Note that it is always possible to produce such a linearization
//! for a finite `Foldable` by setting
//! @code
//! linearization(xs) = fold_left(xs, [], flip(prepend))
//! @endcode
//! for an appropriate definition of `[]` and `prepend`. The notion of
//! linearization is useful for expressing various properties of
//! `Foldable` structures, and is used across the documentation. Also
//! note that `Iterable`s define an [extended version](@ref Iterable-lin)
//! of this allowing for infinite structures.
//!
//!
//! Compile-time Foldables
//! ----------------------
//! A compile-time `Foldable` is a `Foldable` whose total length is known
//! at compile-time. In other words, it is a `Foldable` whose `length`
//! method returns a `Constant` of an unsigned integral type. When
//! folding a compile-time `Foldable`, the folding can be unrolled,
//! because the final number of steps of the algorithm is known at
//! compile-time.
//!
//! Additionally, the `unpack` method is only available to compile-time
//! `Foldable`s. This is because the return _type_ of `unpack` depends
//! on the number of objects in the structure. Being able to resolve
//! `unpack`'s return type at compile-time hence requires the length of
//! the structure to be known at compile-time too.
//!
//! __In the current version of the library, only compile-time `Foldable`s
//! are supported.__ While it would be possible in theory to support
//! runtime `Foldable`s too, doing so efficiently requires more research.
//!
//!
//! Provided conversion to `Sequence`s
//! ----------------------------------
//! Given a tag `S` which is a `Sequence`, an object whose tag is a model
//! of the `Foldable` concept can be converted to an object of tag `S`.
//! In other words, a `Foldable` can be converted to a `Sequence` `S`, by
//! simply taking the linearization of the `Foldable` and creating the
//! sequence with that. More specifically, given a `Foldable` `xs` with a
//! linearization of `[x1, ..., xn]` and a `Sequence` tag `S`, `to<S>(xs)`
//! is equivalent to `make<S>(x1, ..., xn)`.
//! @include example/foldable/to.cpp
//!
//!
//! Free model for builtin arrays
//! -----------------------------
//! Builtin arrays whose size is known can be folded as-if they were
//! homogeneous tuples. However, note that builtin arrays can't be
//! made more than `Foldable` (e.g. `Iterable`) because they can't
//! be empty and they also can't be returned from functions.
//!
//!
//! @anchor monadic-folds
//! Primer on monadic folds
//! -----------------------
//! A monadic fold is a fold in which subsequent calls to the binary
//! function are chained with the monadic `chain` operator of the
//! corresponding Monad. This allows a structure to be folded in a
//! custom monadic context. For example, performing a monadic fold with
//! the `hana::optional` monad would require the binary function to return
//! the result as a `hana::optional`, and the fold would abort and return
//! `nothing` whenever one of the accumulation step would fail (i.e.
//! return `nothing`). If, however, all the reduction steps succeed,
//! then `just` the result would be returned. Different monads will of
//! course result in different effects.
template <typename T>
struct Foldable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_FOLDABLE_HPP
@@ -0,0 +1,139 @@
/*!
@file
Forward declares `boost::hana::Functor`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_FUNCTOR_HPP
#define BOOST_HANA_FWD_CONCEPT_FUNCTOR_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Functor Functor
//! The `Functor` concept represents types that can be mapped over.
//!
//! Intuitively, a [Functor][1] is some kind of box that can hold generic
//! data and map a function over this data to create a new, transformed
//! box. Because we are only interested in mapping a function over the
//! contents of a black box, the only real requirement for being a functor
//! is to provide a function which can do the mapping, along with a couple
//! of guarantees that the mapping is well-behaved. Those requirements are
//! made precise in the laws below. The pattern captured by `Functor` is
//! very general, which makes it widely useful. A lot of objects can be
//! made `Functor`s in one way or another, the most obvious example being
//! sequences with the usual mapping of the function on each element.
//! While this documentation will not go into much more details about
//! the nature of functors, the [Typeclassopedia][2] is a nice
//! Haskell-oriented resource for such information.
//!
//! Functors are parametric data types which are parameterized over the
//! data type of the objects they contain. Like everywhere else in Hana,
//! this parametricity is only at the documentation level and it is not
//! enforced.
//!
//! In this library, the mapping function is called `transform` after the
//! `std::transform` algorithm, but other programming languages have given
//! it different names (usually `map`).
//!
//! @note
//! The word _functor_ comes from functional programming, where the
//! concept has been used for a while, notably in the Haskell programming
//! language. Haskell people borrowed the term from [category theory][3],
//! which, broadly speaking, is a field of mathematics dealing with
//! abstract structures and transformations between those structures.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! 1. `transform`\n
//! When `transform` is specified, `adjust_if` is defined analogously to
//! @code
//! adjust_if(xs, pred, f) = transform(xs, [](x){
//! if pred(x) then f(x) else x
//! })
//! @endcode
//!
//! 2. `adjust_if`\n
//! When `adjust_if` is specified, `transform` is defined analogously to
//! @code
//! transform(xs, f) = adjust_if(xs, always(true), f)
//! @endcode
//!
//!
//! Laws
//! ----
//! Let `xs` be a Functor with tag `F(A)`,
//! \f$ f : A \to B \f$ and
//! \f$ g : B \to C \f$.
//! The following laws must be satisfied:
//! @code
//! transform(xs, id) == xs
//! transform(xs, compose(g, f)) == transform(transform(xs, f), g)
//! @endcode
//! The first line says that mapping the identity function should not do
//! anything, which precludes the functor from doing something nasty
//! behind the scenes. The second line states that mapping the composition
//! of two functions is the same as mapping the first function, and then
//! the second on the result. While the usual functor laws are usually
//! restricted to the above, this library includes other convenience
//! methods and they should satisfy the following equations.
//! Let `xs` be a Functor with tag `F(A)`,
//! \f$ f : A \to A \f$,
//! \f$ \mathrm{pred} : A \to \mathrm{Bool} \f$
//! for some `Logical` `Bool`, and `oldval`, `newval`, `value` objects
//! of tag `A`. Then,
//! @code
//! adjust(xs, value, f) == adjust_if(xs, equal.to(value), f)
//! adjust_if(xs, pred, f) == transform(xs, [](x){
//! if pred(x) then f(x) else x
//! })
//! replace_if(xs, pred, value) == adjust_if(xs, pred, always(value))
//! replace(xs, oldval, newval) == replace_if(xs, equal.to(oldval), newval)
//! fill(xs, value) == replace_if(xs, always(true), value)
//! @endcode
//! The default definition of the methods will satisfy these equations.
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! Structure-preserving functions for Functors
//! -------------------------------------------
//! A mapping between two functors which also preserves the functor
//! laws is called a natural transformation (the term comes from
//! category theory). A natural transformation is a function `f`
//! from a functor `F` to a functor `G` such that for every other
//! function `g` with an appropriate signature and for every object
//! `xs` of tag `F(X)`,
//! @code
//! f(transform(xs, g)) == transform(f(xs), g)
//! @endcode
//!
//! There are several examples of such transformations, like `to<tuple_tag>`
//! when applied to an optional value. Indeed, for any function `g` and
//! `hana::optional` `opt`,
//! @code
//! to<tuple_tag>(transform(opt, g)) == transform(to<tuple_tag>(opt), g)
//! @endcode
//!
//! Of course, natural transformations are not limited to the `to<...>`
//! functions. However, note that any conversion function between Functors
//! should be natural for the behavior of the conversion to be intuitive.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Functor
//! [2]: https://wiki.haskell.org/Typeclassopedia#Functor
//! [3]: http://en.wikipedia.org/wiki/Category_theory
template <typename F>
struct Functor;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_FUNCTOR_HPP
@@ -0,0 +1,111 @@
/*!
@file
Forward declares `boost::hana::Group`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_GROUP_HPP
#define BOOST_HANA_FWD_CONCEPT_GROUP_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Group Group
//! The `Group` concept represents `Monoid`s where all objects have
//! an inverse w.r.t. the `Monoid`'s binary operation.
//!
//! A [Group][1] is an algebraic structure built on top of a `Monoid`
//! which adds the ability to invert the action of the `Monoid`'s binary
//! operation on any element of the set. Specifically, a `Group` is a
//! `Monoid` `(S, +)` such that every element `s` in `S` has an inverse
//! (say `s'`) which is such that
//! @code
//! s + s' == s' + s == identity of the Monoid
//! @endcode
//!
//! There are many examples of `Group`s, one of which would be the
//! additive `Monoid` on integers, where the inverse of any integer
//! `n` is the integer `-n`. The method names used here refer to
//! exactly this model.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! 1. `minus`\n
//! When `minus` is specified, the `negate` method is defaulted by setting
//! @code
//! negate(x) = minus(zero<G>(), x)
//! @endcode
//!
//! 2. `negate`\n
//! When `negate` is specified, the `minus` method is defaulted by setting
//! @code
//! minus(x, y) = plus(x, negate(y))
//! @endcode
//!
//!
//! Laws
//! ----
//! For all objects `x` of a `Group` `G`, the following laws must be
//! satisfied:
//! @code
//! plus(x, negate(x)) == zero<G>() // right inverse
//! plus(negate(x), x) == zero<G>() // left inverse
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! `Monoid`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Group`
//! is automatically defined by setting
//! @code
//! minus(x, y) = (x - y)
//! negate(x) = -x
//! @endcode
//!
//! @note
//! The rationale for not providing a Group model for `bool` is the same
//! as for not providing a `Monoid` model.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Group`s. A function `f : A -> B` is said to
//! be a [Group morphism][2] if it preserves the group structure between
//! `A` and `B`. Rigorously, for all objects `x, y` of data type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! @endcode
//! Because of the `Group` structure, it is easy to prove that the
//! following will then also be satisfied:
//! @code
//! f(negate(x)) == negate(f(x))
//! f(zero<A>()) == zero<B>()
//! @endcode
//! Functions with these properties interact nicely with `Group`s, which
//! is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Group_(mathematics)
//! [2]: http://en.wikipedia.org/wiki/Group_homomorphism
template <typename G>
struct Group;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_GROUP_HPP
@@ -0,0 +1,68 @@
/*!
@file
Forward declares `boost::hana::Hashable`.
@copyright Louis Dionne 2016
@copyright Jason Rice 2016
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_CONCEPT_HASHABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_HASHABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Hashable Hashable
//! The `Hashable` concept represents objects that can be normalized to
//! a type-level hash.
//!
//! In day to day programming, hashes are very important as a way to
//! efficiently lookup objects in maps. While the implementation of
//! maps is very different, the same idea of using hashes for efficient
//! lookup applies in metaprogramming. The `Hashable` concept represents
//! objects that can be summarized (possibly with loss of information) to
//! a type, in a way suitable for use in hash-based data structures. Of
//! course, in order for a hash to be well-behaved, it must obey some laws
//! that are explained below.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `hash`, satisfying the laws below
//!
//!
//! Laws
//! ----
//! First, `hana::hash` must return a `hana::type`. Furthermore, for any
//! two `Hashable` objects `x` and `y`, it must be the case that
//! @code
//! x == y implies hash(x) == hash(y)
//! @endcode
//!
//! where `==` denotes `hana::equal`. In other words, any two objects that
//! compare equal (with `hana::equal`) must also have the same hash.
//! However, the reverse is not true, and two different objects may have
//! the same hash. This situation of two different objects having the same
//! hash is called a _collision_.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::type`, `hana::string`
//!
//!
//! Free model for `IntegralConstant`s
//! ----------------------------------
//! Any `IntegralConstant` is `Hashable`, by normalizing its value to a
//! `hana::integral_constant`. The type of the value held in the normalized
//! `integral_constant` is `unsigned long long` for unsigned integral
//! types, and `signed long long` for signed integral types.
template <typename T>
struct Hashable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_HASHABLE_HPP
@@ -0,0 +1,73 @@
/*!
@file
Forward declares `boost::hana::IntegralConstant`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_INTEGRAL_CONSTANT_HPP
#define BOOST_HANA_FWD_CONCEPT_INTEGRAL_CONSTANT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! The `IntegralConstant` concept represents compile-time integral values.
//!
//! The `IntegralConstant` concept represents objects that hold a
//! `constexpr` value of an integral type. In other words, it describes
//! the essential functionality provided by `std::integral_constant`.
//! An `IntegralConstant` is also just a special kind of `Constant`
//! whose inner value is of an integral type.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! The requirements for being an `IntegralConstant` are quite simple.
//! First, an `IntegralConstant` `C` must be a `Constant` such that
//! `Tag::value_type` is an integral type, where `Tag` is the tag of `C`.
//!
//! Secondly, `C` must have a nested `static constexpr` member named
//! `value`, such that the following code is valid:
//! @code
//! constexpr auto v = C::value;
//! @endcode
//! Because of the requirement that `Tag::value_type` be an integral type,
//! it follows that `C::value` must be an integral value.
//!
//! Finally, it is necessary to specialize the `IntegralConstant` template
//! in the `boost::hana` namespace to tell Hana that a type is a model
//! of `IntegralConstant`:
//! @code
//! namespace boost { namespace hana {
//! template <>
//! struct IntegralConstant<your_custom_tag> {
//! static constexpr bool value = true;
//! };
//! }}
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Constant` (free implementation of `value`)\n
//! The `value` function required to be a `Constant` can be implemented
//! as follows for `IntegralConstant`s:
//! @code
//! value<C>() == C::value
//! @endcode
//! The `to` function must still be provided explicitly for the model
//! of `Constant` to be complete.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
template <typename C>
struct IntegralConstant;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_INTEGRAL_CONSTANT_HPP
@@ -0,0 +1,149 @@
/*!
@file
Forward declares `boost::hana::Iterable`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_ITERABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_ITERABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Iterable Iterable
//! The `Iterable` concept represents data structures supporting external
//! iteration.
//!
//! Intuitively, an `Iterable` can be seen as a kind of container whose
//! elements can be pulled out one at a time. An `Iterable` also provides
//! a way to know when the _container_ is empty, i.e. when there are no
//! more elements to pull out.
//!
//! Whereas `Foldable` represents data structures supporting internal
//! iteration with the ability to accumulate a result, the `Iterable`
//! concept allows inverting the control of the iteration. This is more
//! flexible than `Foldable`, since it allows iterating over only some
//! part of the structure. This, in turn, allows `Iterable` to work on
//! infinite structures, while trying to fold such a structure would
//! never finish.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `at`, `drop_front` and `is_empty`
//!
//!
//! @anchor Iterable-lin
//! The linearization of an `Iterable`
//! ----------------------------------
//! Intuitively, for an `Iterable` structure `xs`, the _linearization_ of
//! `xs` is the sequence of all the elements in `xs` as if they had been
//! put in a (possibly infinite) list:
//! @code
//! linearization(xs) = [x1, x2, x3, ...]
//! @endcode
//!
//! The `n`th element of the linearization of an `Iterable` can be
//! accessed with the `at` function. In other words, `at(xs, n) == xn`.
//!
//! Note that this notion is precisely the extension of the [linearization]
//! (@ref Foldable-lin) notion of `Foldable`s to the infinite case. This
//! notion is useful for expressing various properties of `Iterable`s,
//! and is used for that elsewhere in the documentation.
//!
//!
//! Compile-time `Iterable`s
//! ------------------------
//! A _compile-time_ `Iterable` is an `Iterable` for which `is_empty`
//! returns a compile-time `Logical`. These structures allow iteration
//! to be done at compile-time, in the sense that the "loop" doing the
//! iteration can be unrolled because the total length of the structure
//! is kown at compile-time.
//!
//! In particular, note that being a compile-time `Iterable` has nothing
//! to do with being finite or infinite. For example, it would be possible
//! to create a sequence representing the Pythagorean triples as
//! `integral_constant`s. Such a sequence would be infinite, but iteration
//! on the sequence would still be done at compile-time. However, if one
//! tried to iterate over _all_ the elements of the sequence, the compiler
//! would loop indefinitely, in contrast to your program looping
//! indefinitely if the sequence was a runtime one.
//!
//! __In the current version of the library, only compile-time `Iterable`s
//! are supported.__ While it would be possible in theory to support
//! runtime `Iterable`s, doing it efficiently is the subject of some
//! research. In particular, follow [this issue][1] for the current
//! status of runtime `Iterable`s.
//!
//!
//! Laws
//! ----
//! First, we require the equality of two `Iterable`s to be related to the
//! equality of the elements in their linearizations. More specifically,
//! if `xs` and `ys` are two `Iterable`s of data type `It`, then
//! @code
//! xs == ys => at(xs, i) == at(ys, i) for all i
//! @endcode
//!
//! This conveys that two `Iterable`s must have the same linearization
//! in order to be considered equal.
//!
//! Secondly, since every `Iterable` is also a `Searchable`, we require
//! the models of `Iterable` and `Searchable` to be consistent. This is
//! made precise by the following laws. For any `Iterable` `xs` with a
//! linearization of `[x1, x2, x3, ...]`,
//! @code
//! any_of(xs, equal.to(z)) <=> xi == z
//! @endcode
//! for some _finite_ index `i`. Furthermore,
//! @code
//! find_if(xs, pred) == just(the first xi such that pred(xi) is satisfied)
//! @endcode
//! or `nothing` if no such `xi` exists.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Searchable` (free model)\n
//! Any `Iterable` gives rise to a model of `Searchable`, where the keys
//! and the values are both the elements in the structure. Searching for
//! a key is just doing a linear search through the elements of the
//! structure.
//! @include example/iterable/searchable.cpp
//!
//! 2. `Foldable` for finite `Iterable`s\n
//! Every finite `Iterable` gives rise to a model of `Foldable`. For
//! these models to be consistent, we require the models of both `Foldable`
//! and `Iterable` to have the same linearization.
//!
//! @note
//! As explained above, `Iterable`s are also `Searchable`s and their
//! models have to be consistent. By the laws presented here, it also
//! means that the `Foldable` model for finite `Iterable`s has to be
//! consistent with the `Searchable` model.
//!
//! For convenience, finite `Iterable`s must only provide a definition of
//! `length` to model the `Foldable` concept; defining the more powerful
//! `unpack` or `fold_left` is not necessary (but still possible). The
//! default implementation of `unpack` derived from `Iterable` + `length`
//! uses the fact that `at(xs, i)` denotes the `i`th element of `xs`'s
//! linearization, and that the linearization of a finite `Iterable` must
//! be the same as its linearization as a `Foldable`.
//!
//!
//! Concrete models
//! ---------------
//! `hana::tuple`, `hana::string`, `hana::range`
//!
//!
//! [1]: https://github.com/boostorg/hana/issues/40
template <typename It>
struct Iterable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_ITERABLE_HPP
@@ -0,0 +1,166 @@
/*!
@file
Forward declares `boost::hana::Logical`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_LOGICAL_HPP
#define BOOST_HANA_FWD_CONCEPT_LOGICAL_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Logical Logical
//! The `Logical` concept represents types with a truth value.
//!
//! Intuitively, a `Logical` is just a `bool`, or something that can act
//! like one. However, in the context of programming with heterogeneous
//! objects, it becomes extremely important to distinguish between those
//! objects whose truth value is known at compile-time, and those whose
//! truth value is only known at runtime. The reason why this is so
//! important is because it is possible to branch at compile-time on
//! a condition whose truth value is known at compile-time, and hence
//! the return type of the enclosing function can depend on that truth
//! value. However, if the truth value is only known at runtime, then
//! the compiler has to compile both branches (because any or both of
//! them may end up being used), which creates the additional requirement
//! that both branches must evaluate to the same type.
//!
//! More specifically, `Logical` (almost) represents a [boolean algebra][1],
//! which is a mathematical structure encoding the usual properties that
//! allow us to reason with `bool`. The exact properties that must be
//! satisfied by any model of `Logical` are rigorously stated in the laws
//! below.
//!
//!
//! Truth, falsity and logical equivalence
//! --------------------------------------
//! A `Logical` `x` is said to be _true-valued_, or sometimes also just
//! _true_ as an abuse of notation, if
//! @code
//! if_(x, true, false) == true
//! @endcode
//!
//! Similarly, `x` is _false-valued_, or sometimes just _false_, if
//! @code
//! if_(x, true, false) == false
//! @endcode
//!
//! This provides a standard way of converting any `Logical` to a straight
//! `bool`. The notion of truth value suggests another definition, which
//! is that of logical equivalence. We will say that two `Logical`s `x`
//! and `y` are _logically equivalent_ if they have the same truth value.
//! To denote that some expressions `p` and `q` of a Logical data type are
//! logically equivalent, we will sometimes also write
//! @code
//! p if and only if q
//! @endcode
//! which is very common in mathematics. The intuition behind this notation
//! is that whenever `p` is true-valued, then `q` should be; but when `p`
//! is false-valued, then `q` should be too. Hence, `p` should be
//! true-valued when (and only when) `q` is true-valued.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `eval_if`, `not_` and `while_`
//!
//! All the other functions can be defined in those terms:
//! @code
//! if_(cond, x, y) = eval_if(cond, lazy(x), lazy(y))
//! and_(x, y) = if_(x, y, x)
//! or_(x, y) = if_(x, x, y)
//! etc...
//! @endcode
//!
//!
//! Laws
//! ----
//! As outlined above, the `Logical` concept almost represents a boolean
//! algebra. The rationale for this laxity is to allow things like integers
//! to act like `Logical`s, which is aligned with C++, even though they do
//! not form a boolean algebra. Even though we depart from the usual
//! axiomatization of boolean algebras, we have found through experience
//! that the definition of a Logical given here is largely compatible with
//! intuition.
//!
//! The following laws must be satisfied for any data type `L` modeling
//! the `Logical` concept. Let `a`, `b` and `c` be objects of a `Logical`
//! data type, and let `t` and `f` be arbitrary _true-valued_ and
//! _false-valued_ `Logical`s of that data type, respectively. Then,
//! @code
//! // associativity
//! or_(a, or_(b, c)) == or_(or_(a, b), c)
//! and_(a, and_(b, c)) == and_(and_(a, b), c)
//!
//! // equivalence through commutativity
//! or_(a, b) if and only if or_(b, a)
//! and_(a, b) if and only if and_(b, a)
//!
//! // absorption
//! or_(a, and_(a, b)) == a
//! and_(a, or_(a, b)) == a
//!
//! // left identity
//! or_(a, f) == a
//! and_(a, t) == a
//!
//! // distributivity
//! or_(a, and_(b, c)) == and_(or_(a, b), or_(a, c))
//! and_(a, or_(b, c)) == or_(and_(a, b), and_(a, c))
//!
//! // complements
//! or_(a, not_(a)) is true-valued
//! and_(a, not_(a)) is false-valued
//! @endcode
//!
//! > #### Why is the above not a boolean algebra?
//! > If you look closely, you will find that we depart from the usual
//! > boolean algebras because:
//! > 1. we do not require the elements representing truth and falsity to
//! > be unique
//! > 2. we do not enforce commutativity of the `and_` and `or_` operations
//! > 3. because we do not enforce commutativity, the identity laws become
//! > left-identity laws
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for arithmetic data types
//! ------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For an arithmetic data type `T`, a model of `Logical` is
//! provided automatically by using the result of the builtin implicit
//! conversion to `bool` as a truth value. Specifically, the minimal
//! complete definition for those data types is
//! @code
//! eval_if(cond, then, else_) = cond ? then(id) : else(id)
//! not_(cond) = static_cast<T>(cond ? false : true)
//! while_(pred, state, f) = equivalent to a normal while loop
//! @endcode
//!
//! > #### Rationale for not providing a model for all contextually convertible to bool data types
//! > The `not_` method can not be implemented in a meaningful way for all
//! > of those types. For example, one can not cast a pointer type `T*`
//! > to bool and then back again to `T*` in a meaningful way. With an
//! > arithmetic type `T`, however, it is possible to cast from `T` to
//! > bool and then to `T` again; the result will be `0` or `1` depending
//! > on the truth value. If you want to use a pointer type or something
//! > similar in a conditional, it is suggested to explicitly convert it
//! > to bool by using `to<bool>`.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Boolean_algebra_(structure)
template <typename L>
struct Logical;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_LOGICAL_HPP
@@ -0,0 +1,99 @@
/*!
@file
Forward declares `boost::hana::Metafunction`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_METAFUNCTION_HPP
#define BOOST_HANA_FWD_CONCEPT_METAFUNCTION_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Metafunction Metafunction
//! A `Metafunction` is a function that takes `hana::type`s as inputs and
//! returns a `hana::type` as output.
//!
//! A `Metafunction` is an object satisfying the [FunctionObject][1]
//! concept, but with additional requirements. First, it must be possible
//! to apply a `Metafunction` to arguments whose tag is `type_tag`, and
//! the result of such an application must be an object whose tag is also
//! `type_tag`. Note that `hana::type` and `hana::basic_type` are the
//! only such types.
//!
//! Secondly, a `Metafunction` must provide a nested `::%apply` template
//! which allows performing the same type-level computation as is done by
//! the call operator. In Boost.MPL parlance, a `Metafunction` `F` is
//! hence a [MetafunctionClass][2] in addition to being a `FunctionObject`.
//! Rigorously, the following must be satisfied by any object `f` of type
//! `F` which is a `Metafunction`, and for arbitrary types `T...`:
//! @code
//! f(hana::type_c<T>...) == hana::type_c<F::apply<T...>::type>
//! @endcode
//!
//! Thirdly, to ease the inter-operation of values and types,
//! `Metafunction`s must also allow being called with arguments that
//! are not `hana::type`s. In that case, the result is equivalent to
//! calling the metafunction on the types of the arguments. Rigorously,
//! this means that for arbitrary objects `x...`,
//! @code
//! f(x...) == f(hana::type_c<decltype(x)>...)
//! @endcode
//!
//!
//! Minimal complete definition
//! ---------------------------
//! The `Metafunction` concept does not have a minimal complete definition
//! in terms of tag-dispatched methods. Instead, the syntactic requirements
//! documented above should be satisfied, and the `Metafunction` struct
//! should be specialized explicitly in Hana's namespace.
//!
//!
//! Concrete models
//! ---------------
//! `hana::metafunction`, `hana::metafunction_class`, `hana::template_`
//!
//!
//! Rationale: Why aren't `Metafunction`s `Comparable`?
//! ---------------------------------------------------
//! When seeing `hana::template_`, a question that naturally arises is
//! whether `Metafunction`s should be made `Comparable`. Indeed, it
//! would seem to make sense to compare two templates `F` and `G` with
//! `template_<F> == template_<G>`. However, in the case where `F` and/or
//! `G` are alias templates, it makes sense to talk about two types of
//! comparisons. The first one is _shallow_ comparison, and it determines
//! that two alias templates are equal if they are the same alias
//! template. The second one is _deep_ comparison, and it determines
//! that two template aliases are equal if they alias the same type for
//! any template argument. For example, given `F` and `G` defined as
//! @code
//! template <typename T>
//! using F = void;
//!
//! template <typename T>
//! using G = void;
//! @endcode
//!
//! shallow comparison would determine that `F` and `G` are different
//! because they are two different template aliases, while deep comparison
//! would determine that `F` and `G` are equal because they always
//! expand to the same type, `void`. Unfortunately, deep comparison is
//! impossible to implement because one would have to check `F` and `G`
//! on all possible types. On the other hand, shallow comparison is not
//! satisfactory because `Metafunction`s are nothing but functions on
//! `type`s, and the equality of two functions is normally defined with
//! deep comparison. Hence, we adopt a conservative stance and avoid
//! providing comparison for `Metafunction`s.
//!
//! [1]: http://en.cppreference.com/w/cpp/concept/FunctionObject
//! [2]: http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/metafunction-class.html
template <typename F>
struct Metafunction;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_METAFUNCTION_HPP
@@ -0,0 +1,198 @@
/*!
@file
Forward declares `boost::hana::Monad`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_MONAD_HPP
#define BOOST_HANA_FWD_CONCEPT_MONAD_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Monad Monad
//! The `Monad` concept represents `Applicative`s with the ability to
//! flatten nested levels of structure.
//!
//! Historically, Monads are a construction coming from category theory,
//! an abstract branch of mathematics. The functional programming
//! community eventually discovered how Monads could be used to
//! formalize several useful things like side effects, which led
//! to the wide adoption of Monads in that community. However, even
//! in a multi-paradigm language like C++, there are several constructs
//! which turn out to be Monads, like `std::optional`, `std::vector` and
//! others.
//!
//! Everybody tries to introduce `Monad`s with a different analogy, and
//! most people fail. This is called the [Monad tutorial fallacy][1]. We
//! will try to avoid this trap by not presenting a specific intuition,
//! and we will instead present what monads are mathematically.
//! For specific intuitions, we will let readers who are new to this
//! concept read one of the many excellent tutorials available online.
//! Understanding Monads might take time at first, but once you get it,
//! a lot of patterns will become obvious Monads; this enlightening will
//! be your reward for the hard work.
//!
//! There are different ways of defining a Monad; Haskell uses a function
//! called `bind` (`>>=`) and another one called `return` (it has nothing
//! to do with C++'s `return` statement). They then introduce relationships
//! that must be satisfied for a type to be a Monad with those functions.
//! Mathematicians sometimes use a function called `join` and another one
//! called `unit`, or they also sometimes use other category theoretic
//! constructions like functor adjunctions and the Kleisli category.
//!
//! This library uses a composite approach. First, we use the `flatten`
//! function (equivalent to `join`) along with the `lift` function from
//! `Applicative` (equivalent to `unit`) to introduce the notion of
//! monadic function composition. We then write the properties that must
//! be satisfied by a Monad using this monadic composition operator,
//! because we feel it shows the link between Monads and Monoids more
//! clearly than other approaches.
//!
//! Roughly speaking, we will say that a `Monad` is an `Applicative` which
//! also defines a way to compose functions returning a monadic result,
//! as opposed to only being able to compose functions returning a normal
//! result. We will then ask for this composition to be associative and to
//! have a neutral element, just like normal function composition. For
//! usual composition, the neutral element is the identity function `id`.
//! For monadic composition, the neutral element is the `lift` function
//! defined by `Applicative`. This construction is made clearer in the
//! laws below.
//!
//! @note
//! Monads are known to be a big chunk to swallow. However, it is out of
//! the scope of this documentation to provide a full-blown explanation
//! of the concept. The [Typeclassopedia][2] is a nice Haskell-oriented
//! resource where more information about Monads can be found.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! First, a `Monad` must be both a `Functor` and an `Applicative`.
//! Also, an implementation of `flatten` or `chain` satisfying the
//! laws below for monadic composition must be provided.
//!
//! @note
//! The `ap` method for `Applicatives` may be derived from the minimal
//! complete definition of `Monad` and `Functor`; see below for more
//! information.
//!
//!
//! Laws
//! ----
//! To simplify writing the laws, we use the comparison between functions.
//! For two functions `f` and `g`, we define
//! @code
//! f == g if and only if f(x) == g(x) for all x
//! @endcode
//!
//! With the usual composition of functions, we are given two functions
//! @f$ f : A \to B @f$ and @f$ g : B \to C @f$, and we must produce a
//! new function @f$ compose(g, f) : A \to C @f$. This composition of
//! functions is associative, which means that
//! @code
//! compose(h, compose(g, f)) == compose(compose(h, g), f)
//! @endcode
//!
//! Also, this composition has an identity element, which is the identity
//! function. This simply means that
//! @code
//! compose(f, id) == compose(id, f) == f
//! @endcode
//!
//! This is probably nothing new if you are reading the `Monad` laws.
//! Now, we can observe that the above is equivalent to saying that
//! functions with the composition operator form a `Monoid`, where the
//! neutral element is the identity function.
//!
//! Given an `Applicative` `F`, what if we wanted to compose two functions
//! @f$ f : A \to F(B) @f$ and @f$ g : B \to F(C) @f$? When the
//! `Applicative` `F` is also a `Monad`, such functions taking normal
//! values but returning monadic values are called _monadic functions_.
//! To compose them, we obviously can't use normal function composition,
//! since the domains and codomains of `f` and `g` do not match properly.
//! Instead, we'll need a new operator -- let's call it `monadic_compose`:
//! @f[
//! \mathtt{monadic\_compose} :
//! (B \to F(C)) \times (A \to F(B)) \to (A \to F(C))
//! @f]
//!
//! How could we go about implementing this function? Well, since we know
//! `F` is an `Applicative`, the only functions we have are `transform`
//! (from `Functor`), and `lift` and `ap` (from `Applicative`). Hence,
//! the only thing we can do at this point while respecting the signatures
//! of `f` and `g` is to set (for `x` of type `A`)
//! @code
//! monadic_compose(g, f)(x) = transform(f(x), g)
//! @endcode
//!
//! Indeed, `f(x)` is of type `F(B)`, so we can map `g` (which takes `B`'s)
//! on it. Doing so will leave us with a result of type `F(F(C))`, but what
//! we wanted was a result of type `F(C)` to respect the signature of
//! `monadic_compose`. If we had a joker of type @f$ F(F(C)) \to F(C) @f$,
//! we could simply set
//! @code
//! monadic_compose(g, f)(x) = joker(transform(f(x), g))
//! @endcode
//!
//! and we would be happy. It turns out that `flatten` is precisely this
//! joker. Now, we'll want our joker to satisfy some properties to make
//! sure this composition is associative, just like our normal composition
//! was. These properties are slightly cumbersome to specify, so we won't
//! do it here. Also, we'll need some kind of neutral element for the
//! composition. This neutral element can't be the usual identity function,
//! because it does not have the right type: our neutral element needs to
//! be a function of type @f$ X \to F(X) @f$ but the identity function has
//! type @f$ X \to X @f$. It is now the right time to observe that `lift`
//! from `Applicative` has exactly the right signature, and so we'll take
//! this for our neutral element.
//!
//! We are now ready to formulate the `Monad` laws using this composition
//! operator. For a `Monad` `M` and functions @f$ f : A \to M(B) @f$,
//! @f$ g : B \to M(C) @f$ and @f$ h : C \to M(D) @f$, the following
//! must be satisfied:
//! @code
//! // associativity
//! monadic_compose(h, monadic_compose(g, f)) == monadic_compose(monadic_compose(h, g), f)
//!
//! // right identity
//! monadic_compose(f, lift<M(A)>) == f
//!
//! // left identity
//! monadic_compose(lift<M(B)>, f) == f
//! @endcode
//!
//! which is to say that `M` along with monadic composition is a Monoid
//! where the neutral element is `lift`.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Functor`
//! 2. `Applicative` (free implementation of `ap`)\n
//! When the minimal complete definition for `Monad` and `Functor` are
//! both satisfied, it is possible to implement `ap` by setting
//! @code
//! ap(fs, xs) = chain(fs, [](auto f) {
//! return transform(xs, f);
//! })
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! [1]: https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/
//! [2]: https://wiki.haskell.org/Typeclassopedia#Monad
template <typename M>
struct Monad;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONAD_HPP
@@ -0,0 +1,89 @@
/*!
@file
Forward declares `boost::hana::MonadPlus`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_MONAD_PLUS_HPP
#define BOOST_HANA_FWD_CONCEPT_MONAD_PLUS_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-MonadPlus MonadPlus
//! 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`.
//!
//! @note
//! This documentation does not go into much details about the nature
//! of the MonadPlus concept. However, there is a nice Haskell-oriented
//! [WikiBook][1] going into further details.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `concat` and `empty`
//!
//!
//! Laws
//! ----
//! First, a MonadPlus is required to have a monoidal structure. Hence, it
//! is no surprise that for any MonadPlus `M`, we require `M(T)` to be a
//! valid monoid. However, we do not enforce that `M(T)` actually models
//! the Monoid concept provided by Hana. Further, for all objects `a, b, c`
//! of data type `M(T)`,
//! @code
//! // identity
//! concat(empty<M(T)>(), a) == a
//! concat(a, empty<M(T)>()) == a
//!
//! // associativity
//! concat(a, concat(b, c)) == concat(concat(a, b), c)
//! @endcode
//!
//! Secondly, a MonadPlus is also required to obey the following laws,
//! which represent the fact that `empty<M(T)>()` must be some kind of
//! absorbing element for the `chain` operation. For all objects `a` of
//! data type `M(T)` and functions @f$ f : T \to M(U) @f$,
//! @code
//! chain(empty<M(T)>(), f) == empty<M(U)>()
//! chain(a, always(empty<M(T)>())) == empty<M(U)>()
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Functor`, `Applicative` and `Monad`
//!
//!
//! Concrete models
//! ---------------
//! `hana::optional`, `hana::tuple`
//!
//! [1]: https://en.wikibooks.org/wiki/Haskell/MonadPlus
template <typename M>
struct MonadPlus;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONAD_PLUS_HPP
@@ -0,0 +1,101 @@
/*!
@file
Forward declares `boost::hana::Monoid`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_MONOID_HPP
#define BOOST_HANA_FWD_CONCEPT_MONOID_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Monoid Monoid
//! The `Monoid` concept represents data types with an associative
//! binary operation that has an identity.
//!
//! Specifically, a [Monoid][1] is a basic algebraic structure typically
//! used in mathematics to construct more complex algebraic structures
//! like `Group`s, `Ring`s and so on. They are useful in several contexts,
//! notably to define the properties of numbers in a granular way. At its
//! core, a `Monoid` is a set `S` of objects along with a binary operation
//! (let's say `+`) that is associative and that has an identity in `S`.
//! There are many examples of `Monoid`s:
//! - strings with concatenation and the empty string as the identity
//! - integers with addition and `0` as the identity
//! - integers with multiplication and `1` as the identity
//! - many others...
//!
//! As you can see with the integers, there are some sets that can be
//! viewed as a monoid in more than one way, depending on the choice
//! of the binary operation and identity. The method names used here
//! refer to the monoid of integers under addition; `plus` is the binary
//! operation and `zero` is the identity element of that operation.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `plus` and `zero` satisfying the laws
//!
//!
//! Laws
//! ----
//! For all objects `x`, `y` and `z` of a `Monoid` `M`, the following
//! laws must be satisfied:
//! @code
//! plus(zero<M>(), x) == x // left zero
//! plus(x, zero<M>()) == x // right zero
//! plus(x, plus(y, z)) == plus(plus(x, y), z) // associativity
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Monoid`
//! is automatically defined by setting
//! @code
//! plus(x, y) = (x + y)
//! zero<T>() = static_cast<T>(0)
//! @endcode
//!
//! > #### Rationale for not making `bool` a `Monoid` by default
//! > First, it makes no sense whatsoever to define an additive `Monoid`
//! > over the `bool` type. Also, it could make sense to define a `Monoid`
//! > with logical conjunction or disjunction. However, C++ allows `bool`s
//! > to be added, and the method names of this concept really suggest
//! > addition. In line with the principle of least surprise, no model
//! > is provided by default.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Monoid`s. A function `f : A -> B` is said
//! to be a [Monoid morphism][2] if it preserves the monoidal structure
//! between `A` and `B`. Rigorously, for all objects `x, y` of data
//! type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! f(zero<A>()) == zero<B>()
//! @endcode
//! Functions with these properties interact nicely with `Monoid`s, which
//! is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Monoid
//! [2]: http://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms
template <typename M>
struct Monoid;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONOID_HPP
@@ -0,0 +1,187 @@
/*!
@file
Forward declares `boost::hana::Orderable`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_ORDERABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_ORDERABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Orderable Orderable
//! The `Orderable` concept represents totally ordered data types.
//!
//! Intuitively, `Orderable` objects must define a binary predicate named
//! `less` returning whether the first argument is to be considered less
//! than the second argument. The word "total" means that _distinct_
//! objects must always be ordered; if `a` and `b` are not equal, then
//! exactly one of `less(a, b)` and `less(b, a)` must be true. This is
//! a contrast with weaker kinds of orders that would allow some objects
//! to be incomparable (neither less than nor greater than). Also note
//! that a non-strict total order may always be obtained from a strict
//! total order (and vice-versa) by setting
//! @code
//! a <= b = !(b < a)
//! a < b = !(b <= a)
//! @endcode
//! The non-strict version is used in the description of the laws because
//! it makes them easier to parse for humans, but they could be formulated
//! equivalently using the strict order.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `less`
//!
//! When `less` is defined, the other methods are defined from it using
//! the same definition as mandated in the laws below.
//!
//!
//! Laws
//! ----
//! Rigorously speaking, a [total order][1] `<=` on a set `S` is a binary
//! predicate @f$ <= \;: S \times S \to bool @f$ such that for all
//! `a`, `b`, `c` in `S`,
//! @code
//! if a <= b and b <= a then a == b // Antisymmetry
//! if a <= b and b <= c then a <= c // Transitivity
//! either a <= b or b <= a // Totality
//! @endcode
//! Additionally, the `less`, `greater` and `greater_equal` methods should
//! have the following intuitive meanings:
//! @code
//! a < b if and only if !(b <= a)
//! a > b if and only if b < a
//! a >= b if and only if !(a < b)
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Comparable` (free model)\n
//! Since `Orderable` requires `less_equal` to be a total order, a model
//! of `Comparable` may always be obtained by setting
//! @code
//! equal(x, y) = less_equal(x, y) && less_equal(y, x)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::optional`, `hana::pair`,
//! `hana::string`, `hana::tuple`
//!
//!
//! Free model for `LessThanComparable` data types
//! ----------------------------------------------
//! Two data types `T` and `U` that model the cross-type version of the
//! usual [LessThanComparable][2] C++ concept are automatically a model
//! of `Orderable` by setting
//! @code
//! less(x, y) = (x < y)
//! @endcode
//! The cross-type version of the LessThanComparable concept is analogous
//! to the cross-type version of the EqualityComparable concept presented
//! in [N3351][3], which is compatible with the usual single type
//! definition.
//! However, note that the LessThanComparable concept only requires `<`
//! to be a [strict weak ordering][4], which is a weaker requirement
//! than being a total order. Hence, if `less` is used with objects
//! of a LessThanComparable data type that do not define a total order,
//! some algorithms may have an unexpected behavior. It is the author's
//! opinion that defining `operator<` as a non-total order is a bad idea,
//! but this is debatable and so the design choice of providing a model
//! for LessThanComparable data types is open to debate. Waiting for
//! some user input.
//!
//!
//! Order-preserving functions
//! --------------------------
//! Let `A` and `B` be two `Orderable` data types. A function
//! @f$ f : A \to B@f$ is said to be order-preserving (also called
//! monotone) if it preserves the structure of the `Orderable` concept,
//! which can be rigorously stated as follows. For all objects `x`, `y`
//! of data type `A`,
//! @code
//! if less(x, y) then less(f(x), f(y))
//! @endcode
//! Another important property is that of being order-reflecting, which
//! can be stated as
//! @code
//! if less(f(x), f(y)) then less(x, y)
//! @endcode
//! We say that a function is an order-embedding if it is both
//! order-preserving and order-reflecting, i.e. if
//! @code
//! less(x, y) if and only if less(f(x), f(y))
//! @endcode
//!
//!
//! Cross-type version of the methods
//! ---------------------------------
//! The comparison methods (`less`, `less_equal`, `greater` and
//! `greater_equal`) are "overloaded" to handle distinct data types
//! with certain properties. Specifically, they are defined for
//! _distinct_ data types `A` and `B` such that
//! 1. `A` and `B` share a common data type `C`, as determined by the
//! `common` metafunction
//! 2. `A`, `B` and `C` are all `Orderable` when taken individually
//! 3. @f$\mathrm{to<C>} : A \to C@f$ and @f$\mathrm{to<C>} : B \to C@f$
//! are both order-embeddings as determined by the `is_embedding`
//! metafunction.
//!
//! The method definitions for data types satisfying the above
//! properties are
//! @code
//! less(x, y) = less(to<C>(x), to<C>(y))
//! less_equal(x, y) = less_equal(to<C>(x), to<C>(y))
//! greater_equal(x, y) = greater_equal(to<C>(x), to<C>(y))
//! greater(x, y) = greater(to<C>(x), to<C>(y))
//! @endcode
//!
//!
//! Partial application of the methods
//! ----------------------------------
//! The `less`, `greater`, `less_equal` and `greater_equal` methods can
//! be called in two different ways. First, they can be called like
//! normal functions:
//! @code
//! less(x, y)
//! greater(x, y)
//!
//! less_equal(x, y)
//! greater_equal(x, y)
//! @endcode
//!
//! However, they may also be partially applied to an argument as follows:
//! @code
//! less.than(x)(y) == less(y, x)
//! greater.than(x)(y) == greater(y, x)
//!
//! less_equal.than(x)(y) == less_equal(y, x)
//! greater_equal.than(x)(y) == greater_equal(y, x)
//! @endcode
//!
//! Take good note that the order of the arguments is reversed, so
//! for example `less.than(x)(y)` is equivalent to `less(y, x)`, not
//! `less(x, y)`. This is because those variants are meant to be used
//! with higher order algorithms, where the chosen application order
//! makes sense.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Total_order
//! [2]: http://en.cppreference.com/w/cpp/concept/LessThanComparable
//! [3]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
//! [4]: http://en.wikipedia.org/wiki/Strict_weak_ordering
template <typename Ord>
struct Orderable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_ORDERABLE_HPP
@@ -0,0 +1,103 @@
/*!
@file
Forward declares `boost::hana::Product`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_PRODUCT_HPP
#define BOOST_HANA_FWD_CONCEPT_PRODUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Product Product
//! Represents types that are generic containers of two elements.
//!
//! This concept basically represents types that are like `std::pair`.
//! The motivation for making such a precise concept is similar to the
//! motivation behind the `Sequence` concept; there are many different
//! implementations of `std::pair` in different libraries, and we would
//! like to manipulate any of them generically.
//!
//! Since a `Product` is basically a pair, it is unsurprising that the
//! operations provided by this concept are getting the first and second
//! element of a pair, creating a pair from two elements and other
//! simmilar operations.
//!
//! @note
//! Mathematically, this concept represents types that are category
//! theoretical [products][1]. This is also where the name comes
//! from.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `first`, `second` and `make`
//!
//! `first` and `second` must obviously return the first and the second
//! element of the pair, respectively. `make` must take two arguments `x`
//! and `y` representing the first and the second element of the pair,
//! and return a pair `p` such that `first(p) == x` and `second(p) == y`.
//! @include example/product/make.cpp
//!
//!
//! Laws
//! ----
//! For a model `P` of `Product`, the following laws must be satisfied.
//! For every data types `X` and `Y`, there must be a unique function
//! @f$ \mathtt{make} : X \times Y \to P @f$ such that for every `x`, `y`,
//! @code
//! x == first(make<P>(x, y))
//! y == second(make<P>(x, y))
//! @endcode
//!
//! @note
//! This law is less general than the universal property typically used to
//! define category theoretical products, but it is vastly enough for what
//! we need.
//!
//! This is basically saying that a `Product` must be the most general
//! object able to contain a pair of objects `(P1, P2)`, but nothing
//! more. Since the categorical product is defined by a universal
//! property, all the models of this concept are isomorphic, and
//! the isomorphism is unique. In other words, there is one and only
//! one way to convert one `Product` to another.
//!
//! Another property that must be satisfied by `first` and `second` is
//! that of @ref move-independence, which ensures that we can optimally
//! decompose a `Product` into its two members without making redundant
//! copies.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (free model)\n
//! Two products `x` and `y` are equal iff they are equal element-wise,
//! by comparing the first element before the second element.
//! @include example/product/comparable.cpp
//!
//! 2. `Orderable` (free model)\n
//! Products are ordered using a lexicographical ordering as-if they
//! were 2-element tuples.
//!
//! 3. `Foldable` (free model)\n
//! Folding a `Product` `p` is equivalent to folding a list containing
//! `first(p)` and `second(p)`, in that order.
//!
//!
//! Concrete models
//! ---------------
//! `hana::pair`
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Product_(category_theory)
template <typename P>
struct Product;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_PRODUCT_HPP
@@ -0,0 +1,106 @@
/*!
@file
Forward declares `boost::hana::Ring`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_RING_HPP
#define BOOST_HANA_FWD_CONCEPT_RING_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Ring Ring
//! The `Ring` concept represents `Group`s that also form a `Monoid`
//! under a second binary operation that distributes over the first.
//!
//! A [Ring][1] is an algebraic structure built on top of a `Group`
//! which requires a monoidal structure with respect to a second binary
//! operation. This second binary operation must distribute over the
//! first one. Specifically, a `Ring` is a triple `(S, +, *)` such that
//! `(S, +)` is a `Group`, `(S, *)` is a `Monoid` and `*` distributes
//! over `+`, i.e.
//! @code
//! x * (y + z) == (x * y) + (x * z)
//! @endcode
//!
//! The second binary operation is often written `*` with its identity
//! written `1`, in reference to the `Ring` of integers under
//! multiplication. The method names used here refer to this exact ring.
//!
//!
//! Minimal complete definintion
//! ----------------------------
//! `one` and `mult` satisfying the laws
//!
//!
//! Laws
//! ----
//! For all objects `x`, `y`, `z` of a `Ring` `R`, the following laws must
//! be satisfied:
//! @code
//! mult(x, mult(y, z)) == mult(mult(x, y), z) // associativity
//! mult(x, one<R>()) == x // right identity
//! mult(one<R>(), x) == x // left identity
//! mult(x, plus(y, z)) == plus(mult(x, y), mult(x, z)) // distributivity
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Monoid`, `Group`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Ring` is
//! automatically defined by using the provided `Group` model and setting
//! @code
//! mult(x, y) = (x * y)
//! one<T>() = static_cast<T>(1)
//! @endcode
//!
//! @note
//! The rationale for not providing a Ring model for `bool` is the same
//! as for not providing Monoid and Group models.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Ring`s. A function `f : A -> B` is said to
//! be a [Ring morphism][2] if it preserves the ring structure between
//! `A` and `B`. Rigorously, for all objects `x, y` of data type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! f(mult(x, y)) == mult(f(x), f(y))
//! f(one<A>()) == one<B>()
//! @endcode
//! Because of the `Ring` structure, it is easy to prove that the
//! following will then also be satisfied:
//! @code
//! f(zero<A>()) == zero<B>()
//! f(negate(x)) == negate(f(x))
//! @endcode
//! which is to say that `f` will then also be a `Group` morphism.
//! Functions with these properties interact nicely with `Ring`s,
//! which is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Ring_(mathematics)
//! [2]: http://en.wikipedia.org/wiki/Ring_homomorphism
template <typename R>
struct Ring;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_RING_HPP
@@ -0,0 +1,143 @@
/*!
@file
Forward declares `boost::hana::Searchable`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_SEARCHABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Searchable Searchable
//! The `Searchable` concept represents structures that can be searched.
//!
//! Intuitively, a `Searchable` is any structure, finite or infinite,
//! containing elements that can be searched using a predicate. Sometimes,
//! `Searchable`s will associate keys to values; one can search for a key
//! with a predicate, and the value associated to it is returned. This
//! gives rise to map-like data structures. Other times, the elements of
//! the structure that are searched (i.e. those to which the predicate is
//! applied) are the same that are returned, which gives rise to set-like
//! data structures. In general, we will refer to the _keys_ of a
//! `Searchable` structure as those elements that are used for searching,
//! and to the _values_ of a `Searchable` as those elements that are
//! returned when a search is successful. As was explained, there is no
//! requirement that both notions differ, and it is often useful to have
//! keys and values coincide (think about `std::set`).
//!
//! Some methods like `any_of`, `all_of` and `none_of` allow simple queries
//! to be performed on the keys of the structure, while other methods like
//! `find` and `find_if` make it possible to find the value associated
//! to a key. The most specific method should always be used if one
//! cares about performance, because it is usually the case that heavy
//! optimizations can be performed in more specific methods. For example,
//! an associative data structure implemented as a hash table will be much
//! faster to access using `find` than `find_if`, because in the second
//! case it will have to do a linear search through all the entries.
//! Similarly, using `contains` will likely be much faster than `any_of`
//! with an equivalent predicate.
//!
//! > __Insight__\n
//! > In a lazy evaluation context, any `Foldable` can also become a model
//! > of `Searchable` because we can search lazily through the structure
//! > with `fold_right`. However, in the context of C++, some `Searchable`s
//! > can not be folded; think for example of an infinite set.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `find_if` and `any_of`
//!
//! When `find_if` and `any_of` are provided, the other functions are
//! implemented according to the laws explained below.
//!
//! @note
//! We could implement `any_of(xs, pred)` by checking whether
//! `find_if(xs, pred)` is an empty `optional` or not, and then reduce
//! the minimal complete definition to `find_if`. However, this is not
//! done because that implementation requires the predicate of `any_of`
//! to return a compile-time `Logical`, which is more restrictive than
//! what we have right now.
//!
//!
//! Laws
//! ----
//! In order for the semantics of the methods to be consistent, some
//! properties must be satisfied by any model of the `Searchable` concept.
//! Rigorously, for any `Searchable`s `xs` and `ys` and any predicate `p`,
//! the following laws should be satisfied:
//! @code
//! any_of(xs, p) <=> !all_of(xs, negated p)
//! <=> !none_of(xs, p)
//!
//! contains(xs, x) <=> any_of(xs, equal.to(x))
//!
//! find(xs, x) == find_if(xs, equal.to(x))
//! find_if(xs, always(false_)) == nothing
//!
//! is_subset(xs, ys) <=> all_of(xs, [](auto x) { return contains(ys, x); })
//! is_disjoint(xs, ys) <=> none_of(xs, [](auto x) { return contains(ys, x); })
//! @endcode
//!
//! Additionally, if all the keys of the `Searchable` are `Logical`s,
//! the following laws should be satisfied:
//! @code
//! any(xs) <=> any_of(xs, id)
//! all(xs) <=> all_of(xs, id)
//! none(xs) <=> none_of(xs, id)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::map`, `hana::optional`, `hana::range`, `hana::set`,
//! `hana::string`, `hana::tuple`
//!
//!
//! Free model for builtin arrays
//! -----------------------------
//! Builtin arrays whose size is known can be searched as-if they were
//! homogeneous tuples. However, since arrays can only hold objects of
//! a single type and the predicate to `find_if` must return a compile-time
//! `Logical`, the `find_if` method is fairly useless. For similar reasons,
//! the `find` method is also fairly useless. This model is provided mainly
//! because of the `any_of` method & friends, which are both useful and
//! compile-time efficient.
//!
//!
//! Structure preserving functions
//! ------------------------------
//! Given two `Searchables` `S1` and `S2`, a function
//! @f$ f : S_1(X) \to S_2(X) @f$ is said to preserve the `Searchable`
//! structure if for all `xs` of data type `S1(X)` and predicates
//! @f$ \mathtt{pred} : X \to Bool @f$ (for a `Logical` `Bool`),
//! @code
//! any_of(xs, pred) if and only if any_of(f(xs), pred)
//! find_if(xs, pred) == find_if(f(xs), pred)
//! @endcode
//!
//! This is really just a generalization of the following, more intuitive
//! requirements. For all `xs` of data type `S1(X)` and `x` of data type
//! `X`,
//! @code
//! x ^in^ xs if and only if x ^in^ f(xs)
//! find(xs, x) == find(f(xs), x)
//! @endcode
//!
//! These requirements can be understood as saying that `f` does not
//! change the content of `xs`, although it may reorder elements.
//! As usual, such a structure-preserving transformation is said to
//! be an embedding if it is also injective, i.e. if it is a lossless
//! transformation.
template <typename S>
struct Searchable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
@@ -0,0 +1,165 @@
/*!
@file
Forward declares `boost::hana::Sequence`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_SEQUENCE_HPP
#define BOOST_HANA_FWD_CONCEPT_SEQUENCE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Sequence Sequence
//! The `Sequence` concept represents generic index-based sequences.
//!
//! Compared to other abstract concepts, the Sequence concept is very
//! specific. It represents generic index-based sequences. The reason
//! why such a specific concept is provided is because there are a lot
//! of models that behave exactly the same while being implemented in
//! wildly different ways. It is useful to regroup all those data types
//! under the same umbrella for the purpose of generic programming.
//!
//! In fact, models of this concept are not only _similar_. They are
//! actually _isomorphic_, in a sense that we define below, which is
//! a fancy way of rigorously saying that they behave exactly the same
//! to an external observer.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `Iterable`, `Foldable`, and `make`
//!
//! The `Sequence` concept does not provide basic methods that could be
//! used as a minimal complete definition; instead, it borrows methods
//! from other concepts and add laws to them. For this reason, it is
//! necessary to specialize the `Sequence` metafunction in Hana's
//! namespace to tell Hana that a type is indeed a `Sequence`. Explicitly
//! specializing the `Sequence` metafunction can be seen like a seal
//! saying "this data type satisfies the additional laws of a `Sequence`",
//! since those can't be checked by Hana automatically.
//!
//!
//! Laws
//! ----
//! The laws for being a `Sequence` are simple, and their goal is to
//! restrict the semantics that can be associated to the functions
//! provided by other concepts. First, a `Sequence` must be a finite
//! `Iterable` (thus a `Foldable` too). Secondly, for a `Sequence` tag
//! `S`, `make<S>(x1, ..., xn)` must be an object of tag `S` and whose
//! linearization is `[x1, ..., xn]`. This basically ensures that objects
//! of tag `S` are equivalent to their linearization, and that they can
//! be created from such a linearization (with `make`).
//!
//! While it would be possible in theory to handle infinite sequences,
//! doing so complicates the implementation of many algorithms. For
//! simplicity, the current version of the library only handles finite
//! sequences. However, note that this does not affect in any way the
//! potential for having infinite `Searchable`s and `Iterable`s.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (definition provided automatically)\n
//! Two `Sequence`s are equal if and only if they contain the same number
//! of elements and their elements at any given index are equal.
//! @include example/sequence/comparable.cpp
//!
//! 2. `Orderable` (definition provided automatically)\n
//! `Sequence`s are ordered using the traditional lexicographical ordering.
//! @include example/sequence/orderable.cpp
//!
//! 3. `Functor` (definition provided automatically)\n
//! `Sequence`s implement `transform` as the mapping of a function over
//! each element of the sequence. This is somewhat equivalent to what
//! `std::transform` does to ranges of iterators. Also note that mapping
//! a function over an empty sequence returns an empty sequence and never
//! applies the function, as would be expected.
//! @include example/sequence/functor.cpp
//!
//! 4. `Applicative` (definition provided automatically)\n
//! First, `lift`ing a value into a `Sequence` is the same as creating a
//! singleton sequence containing that value. Second, applying a sequence
//! of functions to a sequence of values will apply each function to
//! all the values in the sequence, and then return a list of all the
//! results. In other words,
//! @code
//! ap([f1, ..., fN], [x1, ..., xM]) == [
//! f1(x1), ..., f1(xM),
//! ...
//! fN(x1), ..., fN(xM)
//! ]
//! @endcode
//! Example:
//! @include example/sequence/applicative.cpp
//!
//! 5. `Monad` (definition provided automatically)\n
//! First, `flaten`ning a `Sequence` takes a sequence of sequences and
//! concatenates them to get a larger sequence. In other words,
//! @code
//! flatten([[a1, ..., aN], ..., [z1, ..., zM]]) == [
//! a1, ..., aN, ..., z1, ..., zM
//! ]
//! @endcode
//! This acts like a `std::tuple_cat` function, except it receives a
//! sequence of sequences instead of a variadic pack of sequences to
//! flatten.\n
//! __Example__:
//! @include example/sequence/monad.ints.cpp
//! Also note that the model of `Monad` for `Sequence`s can be seen as
//! modeling nondeterminism. A nondeterministic computation can be
//! modeled as a function which returns a sequence of possible results.
//! In this line of thought, `chain`ing a sequence of values into such
//! a function will return a sequence of all the possible output values,
//! i.e. a sequence of all the values applied to all the functions in
//! the sequences.\n
//! __Example__:
//! @include example/sequence/monad.types.cpp
//!
//! 6. `MonadPlus` (definition provided automatically)\n
//! `Sequence`s are models of the `MonadPlus` concept by considering the
//! empty sequence as the unit of `concat`, and sequence concatenation
//! as `concat`.
//! @include example/sequence/monad_plus.cpp
//!
//! 7. `Foldable`\n
//! The model of `Foldable` for `Sequence`s is uniquely determined by the
//! model of `Iterable`.
//! @include example/sequence/foldable.cpp
//!
//! 8. `Iterable`\n
//! The model of `Iterable` for `Sequence`s corresponds to iteration over
//! each element of the sequence, in order. This model is not provided
//! automatically, and it is in fact part of the minimal complete
//! definition for the `Sequence` concept.
//! @include example/sequence/iterable.cpp
//!
//! 9. `Searchable` (definition provided automatically)\n
//! Searching through a `Sequence` is equivalent to just searching through
//! a list of the values it contains. The keys and the values on which
//! the search is performed are both the elements of the sequence.
//! @include example/sequence/searchable.cpp
//!
//!
//! Concrete models
//! ---------------
//! `hana::tuple`
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Isomorphism#Isomorphism_vs._bijective_morphism
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename S>
struct Sequence;
#else
template <typename S, typename = void>
struct Sequence : Sequence<S, when<true>> { };
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_SEQUENCE_HPP
@@ -0,0 +1,156 @@
/*!
@file
Forward declares `boost::hana::Struct`.
@copyright Louis Dionne 2013-2017
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_CONCEPT_STRUCT_HPP
#define BOOST_HANA_FWD_CONCEPT_STRUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Struct Struct
//! The `Struct` concept represents `struct`-like user-defined types.
//!
//! The `Struct` concept allows restricted compile-time reflection over
//! user-defined types. In particular, it allows accessing the names of
//! the members of a user-defined type, and also the value of those
//! members. `Struct`s can also be folded, searched and converted to
//! some types of containers, where more advanced transformations can
//! be performed.
//!
//! While all types can _in theory_ be made `Struct`s, only a subset of
//! them are actually interesting to see as such. More precisely, it is
//! only interesting to make a type a `Struct` when it is conceptually
//! a C++ `struct`, i.e. a mostly dumb aggregate of named data. The way
//! this data is accessed is mostly unimportant to the `Struct` concept;
//! it could be through getters and setters, through public members,
//! through non-member functions or it could even be generated on-the-fly.
//! The important part, which is made precise below, is that those accessor
//! methods should be move-independent.
//!
//! Another way to see a `Struct` is as a map where the keys are the names
//! of the members and the values are the values of those members. However,
//! there are subtle differences like the fact that one can't add a member
//! to a `Struct`, and also that the order of the members inside a `Struct`
//! plays a role in determining the equality of `Struct`s, which is not
//! the case for maps.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `accessors`
//!
//! A model of `Struct` is created by specifying a sequence of key/value
//! pairs with the `accessors` function. The first element of a pair in
//! this sequence represents the "name" of a member of the `Struct`, while
//! the second element is a function which retrieves this member from an
//! object. The "names" do not have to be in any special form; they just
//! have to be compile-time `Comparable`. For example, it is common to
//! provide "names" that are `hana::string`s representing the actual names
//! of the members, but one could provide `hana::integral_constant`s just
//! as well. The values must be functions which, when given an object,
//! retrieve the appropriate member from it.
//!
//! There are several ways of providing the `accessors` method, some of
//! which are more flexible and others which are more convenient. First,
//! one can define it through tag-dispatching, as usual.
//! @snippet example/struct.mcd.tag_dispatching.cpp main
//!
//! Secondly, it is possible to provide a nested `hana_accessors_impl`
//! type, which should be equivalent to a specialization of
//! `accessors_impl` for tag-dispatching. However, for a type `S`, this
//! technique only works when the data type of `S` is `S` itself, which
//! is the case unless you explicitly asked for something else.
//! @snippet example/struct.mcd.nested.cpp main
//!
//! Finally, the most convenient (but least flexible) option is to use
//! the `BOOST_HANA_DEFINE_STRUCT`, the `BOOST_HANA_ADAPT_STRUCT` or the
//! `BOOST_HANA_ADAPT_ADT` macro, which provide a minimal syntactic
//! overhead. See the documentation of these macros for details on how
//! to use them.
//!
//! Also note that it is not important that the accessor functions retrieve
//! an actual member of the struct (e.g. `x.member`). Indeed, an accessor
//! function could call a custom getter or even compute the value of the
//! member on the fly:
//! @snippet example/struct.custom_accessor.cpp main
//!
//! The only important thing is that the accessor functions are
//! move-independent, a notion which is defined below.
//!
//!
//! @anchor move-independence
//! Move-independence
//! -----------------
//! The notion of move-independence presented here defines rigorously
//! when it is legitimate to "double-move" from an object.
//!
//! A collection of functions `f1, ..., fn` sharing the same domain is
//! said to be _move-independent_ if for every fresh (not moved-from)
//! object `x` in the domain, any permutation of the following statements
//! is valid and leaves the `zk` objects in a fresh (not moved-from) state:
//! @code
//! auto z1 = f1(std::move(x));
//! ...
//! auto zn = fn(std::move(x));
//! @endcode
//!
//! @note
//! In the special case where some functions return objects that can't be
//! bound to with `auto zk =` (like `void` or a non-movable, non-copyable
//! type), just pretend the return value is ignored.
//!
//! Intuitively, this ensures that we can treat `f1, ..., fn` as
//! "accessors" that decompose `x` into independent subobjects, and
//! that do so without moving from `x` more than that subobject. This
//! is important because it allows us to optimally decompose `Struct`s
//! into their subparts inside the library.
//!
//!
//! Laws
//! ----
//! For any `Struct` `S`, the accessors in the `accessors<S>()` sequence
//! must be move-independent, as defined above.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (free model)\n
//! `Struct`s are required to be `Comparable`. Specifically, two `Struct`s
//! of the same data type `S` must be equal if and only if all of their
//! members are equal. By default, a model of `Comparable` doing just that
//! is provided for models of `Struct`. In particular, note that the
//! comparison of the members is made in the same order as they appear in
//! the `hana::members` sequence.
//! @include example/struct/comparable.cpp
//!
//! 2. `Foldable` (free model)\n
//! A `Struct` can be folded by considering it as a list of pairs each
//! containing the name of a member and the value associated to that
//! member, in the same order as they appear in the `hana::members`
//! sequence. By default, a model of `Foldable` doing just that is
//! provided for models of the `Struct` concept.
//! @include example/struct/foldable.cpp
//! Being a model of `Foldable` makes it possible to turn a `Struct`
//! into basically any `Sequence`, but also into a `hana::map` by simply
//! using the `to<...>` function!
//! @include example/struct/to.cpp
//!
//! 3. `Searchable` (free model)\n
//! A `Struct` can be searched by considering it as a map where the keys
//! are the names of the members of the `Struct`, and the values are the
//! members associated to those names. By default, a model of `Searchable`
//! is provided for any model of the `Struct` concept.
//! @include example/struct/searchable.cpp
template <typename S>
struct Struct;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_STRUCT_HPP