[section:concepts Concepts]

[heading Expression]

_Expr_ is the central concept in _yap_.  It must contain at least an _kind_
and a _tuple_ of values.

Here is a summary of the requirements on _Expr_.  In the tables below, `E` is
a type that models _Expr_; `e` is an object of type `E`; `Tuple` is an
instantiation of _tuple_; and `t` is an object of type `Tuple`.

[table Expression Requirements
    [[Expression]    [Type]     [Description]                           [Notes]]
    [[`E::kind`]     [_kind_]   [ The kind of expression `E` is. ]      [ Must be a compile-time constant. ]]
    [[`e.elements`]  [`Tuple`]  [ The child expressions of `e`. ]       [ The types of the elements must be appropriate to the kind of the expression. ]]
    [[`E e{t}`]      []         [ Construction/initialization of `e`. ] [ `t` must be stored in `e.elements`. ]]
]

As stated above, the `elements` data member must match the kind of the expression:

[table Expression Requirements
    [[`E::kind`]                [`hana::size(e.elements)`] [Possible Tuple Element Types] [Notes]]

    [[`expr_kind::expr_ref`]    [1]                   [ Any non-_expr_ref_ _Expr_. ] []]
    [[`expr_kind::terminal`]    [1]                   [ Any non-_Expr_. ] [A terminal with a _placeholder_ value will be treated as a placeholder. ]]
    [[Any unary operator]       [1]                   [ Any _Expr_. ] []]
    [[Any binary operator]      [2]                   [ Any _Expr_. ] []]
    [[`expr_kind::if_else`]     [3]                   [ Any _Expr_. ] []]
    [[`expr_kind::call`]        [Any number >= 1.]    [ Any _Expr_. ] []]
]

[heading ExpressionTemplate]

_ExprTmpl_ is any template with two parameters that, when instantiated with an
_kind_ and a _tuple_, results in an _Expr_.

[heading Transform]

_xform_ takes a _XForm_ as its second parameter.  A _XForm_ is a _Callable_
that takes expressions and returns values of unconstrained type.  There are
two sorts of overloads _XForm_ may use: _ExprXForm_ and _TagXForm_.

A _XForm_ may have any number of overloads, including none.

[heading ExpressionTransform]

_ExprXForm_ takes an _Expr_ as its only parameter.  Here are some examples.

This one takes any _Expr_:

    struct xform
    {
        template <typename Expr>
        auto operator() (Expr const & expr)
        {
            // ...
        }
    };

This one takes any type of _Expr_ that satisfies the constraints imposed by
its template parameters:

    template <typename Expr1, typename Expr2, typename Expr3>
    decltype(auto) xform (
        boost::yap::expression<
            boost::yap::expr_kind::plus,
            boost::hana::tuple<
                boost::yap::expression<
                    boost::yap::expr_kind::multiplies,
                    boost::hana::tuple<
                        Expr1,
                        Expr2
                    >
                >,
                Expr3
            >
        > const & expr
    ) {
        // ...
    }

This one takes only a specific type:

    decltype(auto) xform (
        decltype(term<number>{{0.0}} * number{} + number{}) const & expr
    ) {
        // ...
    }

[heading TagTransform]

_TagXForm_ takes a tag-type as its first parameter, and the individual
elements of an expression as the remaining parameters.

Tags are named such that the tag for an expression with _kind_
`expr_kind::foo` is named `foo_tag`.  Here are some examples.

This one takes any terminal that contains a `user::number` (or reference to
such a terminal):

    struct xform
    {
        decltype(auto) operator() (boost::yap::terminal_tag, user::number const & n)
        {
            // ...
        }
    };

This one takes any plus expression that contains a pair of `user::number`
terminals (or references to terminals):

    decltype(auto) xform (boost::yap::plus_tag, user::number lhs, user::number rhs)
    {
        // ...
    }

This one takes any negation expression:

    struct xform
    {
        template <typename Expr>
        decltype(auto) operator() (boost::yap::negate_tag, Expr const & expr)
        {
            // ...
        }
    };

This one takes any call expression with two terminals (or references to
terminals) containing values convertible to `double`:

    struct xform
    {
        decltype(auto) operator() (boost::yap::call_tag, tag_type, double a, double b)
        {
            // ...
        }
    }

[endsect]
