intro.qbk 3.96 KB
[section Introduction]

"I like to start documentation with a quote.  A nice, pithy one."

['[*_emdash_ Eric Niebler (paraphrased)]]

[heading Motivation]

_Ets_ are rad.  They are used in lots of libraries; here are just three of the
most impressive:

* _spirit_ allows you to write an EBNF-style grammar that gets transformed
  into a PEG parser.

* _eigen_ allows you to do linear algebra using a very natural and
  mathematical expression syntax that _eigen_ uses to heavily optimize your
  expressions.

* _nt2_ takes slightly modified MatLab code and allows it to be parsed and run
  as highly optimized C++ code.

However, this can come at a high cost.  _Ets_ are costly to implement and
maintain.  Each of _eigen_ and Boost.Ublas has a large volume of complex _et_
code that cannot be reused elsewhere.

With the language facilities available in the C++14 and C++17 standards, an
_et_ library is now straightforward to write and use, and has very reasonable
compile times.

As a quick example, let's say we are doing a bit of matrix math, and we write
this statement:

    D = A * B + C;

in which all the variables are matrices.  It turns out that making a temporary
for `A * B` and then another temporary for the resulting product plus `C` is
very inefficient.  Most matrix math libraries will have a single function that
does it in one go:

    mul_add_assign(D, A, B, C);

If you use a matrix library that offers both kinds of syntax, you have to
notice when some bit of operator-using code should be replaced with some more
efficient function; this is tedious and error-prone.  If the library does not
provide the operator syntax at all, only providing the more-efficient function
calls, code using the library is a lot less writable and readable.

Using _yap_, you can write some library code that enables expressions like `D
= A * B + C` to be automatically transformed into expressions like
`mul_add_assign(D, A, B, C)`.

Consider another example.  Many of us have used Unix command line tools to
remove duplicate lines in a file:

    sort file_with_duplicates | uniq > file_without_duplicates

We can do something very similar with the standard algorithms, of course:

[typical_sort_unique_usage]

However, it would be much better if our code did exactly that, but with a more
concise syntax:

[pipable_sort_unique_usage]

This looks much more similar to the Unix command line above.  (Let's pretend
that _range_v3_ doesn't already do almost exactly this.)

_yap_ can be used to do both of these things, in a pretty small amount of
code.  In fact, you can jump right into the _pipable_algorithms_ example if
you want to see how the second one can be implemented.

[heading Features]

* Simple _ExprTmpl_ and _Expr_ concepts easily modeled by user code.  Member
  and non-member functions on _ExprTmpls_ and _Exprs_ can be added with
  compact macros, and a reference template that models _ExprTmpl_ exists for
  prototyping or experimentation.

* Evaluation of _yap_ expressions matches the semantics of builtin C++
  expressions as closely as possible.  This leads to clearer understanding of
  the semantics of expression evaluation, because the definitions are local to
  the types involved.

* Expressions may be transformed explicitly in a user-defined way.  This is
  accomplished with overloaded call operators in a transform class, which are
  matched against subexpressions in the overall expression.  While these
  member functions may transform a subexpression into anything, a common
  pattern is to transform only some subexpressions into either new
  subexpressions or appropriate values and to leave other subexpressions
  unchanged.  This `evaluate(transform(expr))` idiom is expected to be one of
  the most common ways of using Yap to manipulate and evaluate expressions.

* Functions that operate on or create expressions.  Functions are provided
  (and used within _yap_) that manipulate expressions or their subexpressions.
  These simplify the process of writing user-defined transforms, for example.

[endsect]