1[section Examples] 2 3Most of these examples are patterned after the examples from Boost.Proto. In 4part, this was done to underscore where _yap_ can do what Proto can, and where 5it cannot. 6 7Where possible, a Proto-derived example uses syntax in `main()` identical to 8that in the original Proto example. 9 10If you don't know anything about Proto, don't worry. The examples are useful 11on their own. 12 13 14[section Hello World] 15 16Remember how I mentioned earlier that _yap_ does things in a completely lazy 17way? _yap_ doesn't ever evaluate your expression eagerly. Eager evaluation 18can be done, but it's a bit of code. 19 20[hello_world] 21 22[endsect] 23 24 25[section Hello World Redux] 26 27That's better! Sort of.... We created a custom expression template with an 28eager stream operator. This gives us eager evaluation, but gives away all the 29lazy AST building-then-evaluating that we're using _ets_ for in the first 30place. In this simple example, we don't really need it. 31 32[hello_world_redux] 33 34[endsect] 35 36 37[section Minimal] 38 39`minimal_expr` below models _ExprTmpl_; since it has no operators, an 40expression must be built manually. 41 42First, the template itself: 43 44[minimal_template] 45 46This can be used to make a `minimal_expr` plus expression: 47 48[minimal_template_manual_construction] 49 50You can evaluate, transform, or otherwise operate on `minimal_expr` 51expressions using the functions in _yap_ that accept an _Expr_: 52 53[minimal_template_evaluation] 54 55[note Don't use _yap_ this way. Use the operator macros instead. This is an 56example contrived only to show you the minimum requirements on a 57_yap_-compatible template.] 58 59[endsect] 60 61 62[section Calc1] 63 64This is the first of several calculator-building examples derived from Proto. 65This first one just builds lazy expressions with placeholders, and evaluates 66them. Here we can first see how much C++14-and-later language features help 67the end user _emdash_ the Proto version is much, much longer. 68 69[calc1] 70 71[endsect] 72 73 74[section Calc2] 75 76The Proto Calc2 example turns the expressions from Calc1 into callable 77objects. Using _yap_ you can do this in two ways. 78 79You can just use lambdas to wrap the expressions: 80 81[calc2a] 82 83Or you can use _make_expr_fn_ to make a callable object from your expression: 84 85[calc2b] 86 87[endsect] 88 89 90[section Calc3] 91 92Here, we introduce a _XForm_ used to calculate expression arity, and 93`static_assert()` that the number of parameters passed by the caller matches 94the arity. 95 96[note The `get_arity` _XForm_ doesn't produce an _Expr_, and it does not have 97to. _XForms_ may produce _Exprs_ or arbitrary values. They may also have 98arbitrary side effects, and may be stateful.] 99 100[calc3] 101 102[endsect] 103 104 105[section Lazy Vector] 106 107Finally, it starts to get interesting! This example shows how you can add 108plus and other operations to sequences of data without creating temporaries 109and allocating memory. 110 111[note In this example, we see a terminal type that owns the storage of its 112value, a `std::vector<double>`. See the Vector example later on to see a 113terminal type that does not.] 114 115[lazy_vector] 116 117[endsect] 118 119 120[section Self-Evaluating Expressions] 121 122In most of the examples, we've seen _yap_ expressions captured, transformed, 123and/or evaluated either manually, or within certain operations that always do 124certain transformations (as in the `operator[]` in the _lazy_vector_ example). 125 126Sometimes, you want the transfrmations to happen just before a _yap_ 127expression is used by non-_yap_-aware code. At other times, you might want an 128entire _yap_ expression to be evaluated if it appears by itself in a statement 129(i.e. as an expression statement). 130 131This example uses C++17's `if constexpr ()`, simply because it makes the 132example shorter and easier to digest. The `if constexpr ()` bits are not 133strictly necessary. 134 135[self_evaluation] 136 137[endsect] 138 139 140[section TArray] 141 142Proto refers to this as the "mini-library for linear algebra" example. It 143shows how quite complicated expressions involving sequences can be evaluated 144elementwise, requiring no temporaries. 145 146[note The original Proto example used a terminal that contained an array of 147three `int`s; _yap_ cannot represent this, and so this example uses a 148`std::array<T, 3>` instead. _yap_ decays `int[3]` to `int *`, since that is 149what is done in a C++ expression. See _how_treated_ for details.] 150 151[tarray] 152 153[endsect] 154 155 156[section Vec3] 157 158An example using 3-space vectors, a bit like the tarray example. 159 160[vec3] 161 162[endsect] 163 164 165[section Vector] 166 167So far we've only seen examples with custom terminals that own the values in 168the expressions we operate on. What happens when you've got types that you 169want to operate on, non-intrusively? Here's how you might do it with 170`std::vector<>`s: 171 172[vector] 173 174[note Though this example only provides overloads for the operations we want 175to define over `std::vector<>`s, the result of each of those operations is an 176_expr_, which uses *all* the operator overloads. If we wanted to restrict the 177operations on the results too, we could have defined a custom expression 178template with the desired operations, and used that instead of _expr_ in the 179operator macros.] 180 181[endsect] 182 183 184[section Mixed] 185 186This is a lot like the previous Vector example, except that it operates on 187`std::vector<>`s and `std::list<>`s in the same expression. 188 189[mixed] 190 191[endsect] 192 193 194[section Map Assign] 195 196An implementation of `map_list_of()` from Boost.Assign using _yap_. 197 198[map_assign] 199 200[note `map_list_of_expr` defines a generic call operator that matches any 201call, including one with the wrong number of arguments. This could be fixed 202by adding a `static_assert()` to the `map_list_of_expr` template, or by 203hand-writing the call operator with SFNIAE or concept constraints.] 204 205[endsect] 206 207 208[section Future Group] 209 210An implementation of Howard Hinnant's design for /future groups/. 211 212[future_group] 213 214[endsect] 215 216 217[section Autodiff] 218 219Here we adapt an [@https://en.wikipedia.org/wiki/Automatic_differentiation 220automatic differentiation] library to use _yap_ for specifying the equations 221it operates on. 222 223Autodiff is a pretty small library, and doesn't cover every possible input 224expression. What it covers is simple arithmetic, and the well-known functions 225`sin`, `cos`, `sqrt`, and `pow`. 226 227Here is how you would form an input to the library using its API. This is 228taken from the test program that comes with the library. 229 230[autodiff_original_node_builder] 231 232I have a *lot* of trouble understanding what's going on here, and even more 233verifying that the expression written in the comment is actually what the code 234produces. Let's see if we can do better. 235 236First, we start with a custom expression template, `autodiff_expr`. It 237supports simple arithmetic, but notice it has no call operator _emdash_ we 238don't want `(a + b)()` to be a valid expression. 239 240[autodiff_expr_template_decl] 241 242We're going to be using a lot of placeholders in our Autodiff expressions, and 243it sure would be nice if they were `autodiff_expr`s and not _exprs_, so that 244only our desired operators are in play. To do this, we define an operator 245that produces placeholder literals, using the _literal_op_m_ macro: 246 247[autodiff_expr_literals_decl] 248 249Now, how about the functions we need to support, and where do we put the call 250operator? In other examples we created terminal subclasses or templates to 251get special behavior on terminals. In this case, we want to create a 252function-terminal template: 253 254[autodiff_function_terminals] 255 256`OPCODE` is an enumeration in Autodiff. We use it as a non-type template 257parameter for convenience when declaring `sin_` and friends. All we really 258need is for the `OPCODE` to be the value of the terminals we produce, and for 259these function-terminals to have the call operator. 260 261[note Using _member_call_m_ is a bit loose here, because it defines a variadic 262template. We could have written unary call operators to ensure that the user 263can't write call expressions with the wrong number of arguments.] 264 265Now, some tranforms: 266 267[autodiff_xform] 268 269We need a function to tie everything together, since the transforms cannot 270fill in the values for the placeholders. 271 272[autodiff_to_node] 273 274Finally, here is the _yap_ version of the function we started with: 275 276[autodiff_yap_node_builder] 277 278[endsect] 279 280[section Transforming Terminals Only] 281 282Sometimes it can be useful only to transform the terminals in an expression. 283For instance, if you have some type you use for SIMD operations called 284`simd<double>`, you may want to replace all the `double` terminals with 285`simd<double>`. Perhaps you just want to change out `double` for `float`, or 286`int` for `std::size_t`. You get the idea. 287 288In this example, we're replacing all the terminals with something essentially 289arbitrary, the sequence of integer terminals `N, N + 1, N + 2, ...`. This 290makes it easier to observe the result of the replacement in a simple example. 291 292[transform_terminals] 293 294[endsect] 295 296[section Pipable Algorithms] 297 298Let's revisit the pipable standard algorithm example from the intro. Here's 299how you might implement it. 300 301[pipable_algorithms] 302 303[endsect] 304 305[section Boost.Phoenix-style `let()`] 306 307Boost.Phoenix has a thing called _let_. It introduces named reusable values 308that are usable in subsequent expressions. This example is something simliar, 309though not exactly like Phoenix's version. In Phoenix, a let placeholder is 310only evaluated once, whereas the example below does something more like macro 311substitution; each let-placeholder is replaced with its initializing 312expression everywhere it is used. 313 314This example uses C++17's `if constexpr ()`, simply because it makes the 315example shorter and easier to digest. The `if constexpr ()` bits are not 316strictly necessary. 317 318[let] 319 320[endsect] 321 322[endsect] 323