| [library Phoenix |
| [quickbook 1.3] |
| [version 2.0] |
| [authors [de Guzman, Joel], [Marsden, Dan]] |
| [copyright 2002 2003 2004 2005 Joel de Guzman, Dan Marsden] |
| [category string-text] |
| [purpose Lambda Expressions in C++] |
| [license |
| Distributed under the Boost Software License, Version 1.0. |
| (See accompanying file LICENSE_1_0.txt or copy at |
| [@http://www.boost.org/LICENSE_1_0.txt]) |
| ] |
| ] |
| |
| [/ September 2002] |
| [/ September 2004] |
| [/ September 2005] |
| |
| [/ Some links] |
| |
| [def __note__ [$images/note.png]] |
| [def __alert__ [$images/alert.png]] |
| [def __tip__ [$images/tip.png]] |
| |
| [def __spirit__ [@http://spirit.sourceforge.net Spirit]] |
| [def __haskell__ [@http://www.haskell.org Haskell]] |
| [def __mpl__ [@http://www.boost.org/libs/mpl/index.html MPL]] |
| [def __bll__ [@http://www.boost.org/libs/lambda/doc/index.html BLL]] |
| [def __fcpp__ [@http://www.cc.gatech.edu/~yannis/fc++/ FC++]] |
| [def __spirit_repo__ [@http://spirit.sourceforge.net/repository/applications/show_contents.php Spirit Repository]] |
| [def __spirit_list__ [@https://lists.sourceforge.net/lists/listinfo/spirit-general Spirit Mailing List]] |
| [def __spirit_general__ [@news://news.gmane.org/gmane.comp.spirit.general Spirit General NNTP news portal]] |
| [def __gmane__ [@http://www.gmane.org Gmane]] |
| [def __mlist_archive__ [@http://news.gmane.org/gmane.comp.parsers.spirit.general]] |
| [def __forwarding__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm Forwarding Function Problem]] |
| [def __boost_mpl__ [@http://boost.org/libs/mpl/doc/index.html Boost.MPL]] |
| [def __boost_range__ [@http://boost.org/libs/range/index.html Boost.Range]] |
| |
| [section Preface] |
| |
| [:['Functional programming is so called because a program consists entirely of |
| functions. The main program itself is written as a function which receives the |
| program's input as its argument and delivers the program's output as its result. |
| Typically the main function is defined in terms of other functions, which in |
| turn are defined in terms of still more functions until at the bottom level the |
| functions are language primitives.]] |
| |
| [:*John Hughes*-- /Why Functional Programming Matters/] |
| |
| [$images/lambda_cpp.png] |
| |
| [h2 Description] |
| |
| Phoenix enables Functional Programming (FP) in C++. The design and |
| implementation of Phoenix is highly influenced by __fcpp__ by Yannis Smaragdakis |
| and Brian McNamara and the __bll__ (Boost Lambda Library) by Jaakko Jaarvi and |
| Gary Powell. Phoenix is a blend of FC++ and BLL using the implementation |
| techniques used in the __spirit__ inline parser. Phoenix version 2, this |
| version, will probably be the last release of the library. Phoenix v2 will be |
| the basis of the Phoenix and __bll__ merger. |
| |
| Phoenix is a header only library. It is extremely modular by design. One can |
| extract and use only a small subset of the full library, literally tearing the |
| library into small pieces, without fear that the pieces won't work anymore. The |
| library is organized in highly independent modules and layers. |
| |
| [h2 How to use this manual] |
| |
| The Phoenix library is organized in logical modules. This documentation |
| provides a user's guide and reference for each module in the library. A simple |
| and clear code example is worth a hundred lines of documentation; therefore, the |
| user's guide is presented with abundant examples annotated and explained in |
| step-wise manner. The user's guide is based on examples: lots of them. |
| |
| As much as possible, forward information (i.e. citing a specific piece of |
| information that has not yet been discussed) is avoided in the user's manual |
| portion of each module. In many cases, though, it is unavoidable that advanced |
| but related topics not be interspersed with the normal flow of discussion. To |
| alleviate this problem, topics categorized as "advanced" may be skipped at first |
| reading. |
| |
| Some icons are used to mark certain topics indicative of their relevance. These |
| icons precede some text to indicate: |
| |
| [table Icons |
| [[Icon] [Name] [Meaning]] |
| [[__note__] [Note] [Information provided is auxiliary but will |
| give the reader a deeper insight into a specific |
| topic. May be skipped.]] |
| [[__alert__] [Alert] [Information provided is of utmost importance.]] |
| [[__tip__] [Tip] [A potentially useful and helpful piece of |
| information.]] |
| ] |
| |
| This documentation is automatically generated by Spirit QuickBook documentation |
| tool. QuickBook can be found in the __spirit_repo__. |
| |
| [h2 Support] |
| |
| Please direct all questions to Spirit's mailing list. You can subscribe to the |
| __spirit_list__. The mailing list has a searchable archive. A search link to |
| this archive is provided in __spirit__'s home page. You may also read and post |
| messages to the mailing list through __spirit_general__ (thanks to __gmane__). |
| The news group mirrors the mailing list. Here is a link to the archives: |
| __mlist_archive__. |
| |
| [h2 [*/...To my dear daughter, Phoenix/]] |
| |
| [endsect] |
| |
| [section Introduction] |
| |
| [$images/banner.png] |
| |
| The Phoenix library enables FP techniques such as higher order functions, |
| /lambda/ (unnamed functions), /currying/ (partial function application) and lazy |
| evaluation in C++. The focus is more on usefulness and practicality than purity, |
| elegance and strict adherence to FP principles. |
| |
| FP is a programming discipline that is not at all tied to a specific language. |
| FP as a programming discipline can, in fact, be applied to many programming |
| languages. In the realm of C++ for instance, we are seeing more FP techniques |
| being applied. C++ is sufficiently rich to support at least some of the most |
| important facets of FP. C++ is a multi-paradigm programming language. It is not |
| only procedural. It is not only object oriented. Beneath the core of the |
| standard C++ library, a closer look into STL gives us a glimpse of FP already in |
| place. It is obvious that the authors of STL know and practice FP. In the near |
| future, we shall surely see more FP trickle down into the mainstream. |
| |
| The truth is, most of the FP techniques can coexist quite well with the standard |
| object oriented and imperative programming paradigms. When we are using STL |
| algorithms and functors (function objects) for example, we are already doing FP. |
| Phoenix is an evolutionary next step. |
| |
| [endsect] |
| |
| [section Starter Kit] |
| |
| Most "quick starts" only get you a few blocks from where you are. From there, |
| you are on your own. Yet, typically, you'd want to get to the next city. This |
| starter kit shall be as minimal as possible, yet packed as much power as |
| possible. |
| |
| So you are busy and always on the go. You do not wish to spend a lot of time |
| studying the library. You wish to be spared the details for later when you need |
| it. For now, all you need to do is to get up to speed as quickly as possible and |
| start using the library. If this is the case, this is the right place to start. |
| |
| This chapter is by no means a thorough discourse of the library. For more |
| information on Phoenix, please take some time to read the rest of the User's |
| Guide. Yet, if you just want to use the library quickly, now, this chapter will |
| probably suffice. Rather than taking you to the details of the library, we shall |
| try to provide you with annotated exemplars instead. Hopefully, this will get |
| you into high gear quickly. |
| |
| [h2 Functors everywhere] |
| |
| Phoenix is built on function objects (functors). The functor is the main |
| building block. We compose functors to build more complex functors... to build |
| more complex functors... and so on. Almost everything is a functor. |
| |
| [note Functors are so ubiquitous in Phoenix that, in the manual, the |
| words /"functor"/ and /"function"/ are used interchangeably.] |
| |
| [section Values] |
| |
| Values are functions! Examples: |
| |
| val(3) |
| val("Hello, World") |
| |
| The first evaluates to a nullary function (a function taking no arguments) that |
| returns an `int`, `3`. The second evaluates to a nullary function that returns |
| a `char const(&)[13]`, `"Hello, World"`. |
| |
| [h2 Lazy Evaluation] |
| |
| Confused? `val(3)` is a unary function, you say? Yes it is. However, read |
| carefully: /"evaluates to a nullary function"/. `val(3)` evaluates to (returns) a |
| nullary function. Aha! `val(3)` returns a function! So, since `val(3)` returns a |
| function, you can invoke it. Example: |
| |
| cout << val(3)() << endl; |
| |
| (See [@../../example/users_manual/values.cpp values.cpp]) |
| |
| [blurb __tip__ Learn more about values [link phoenix.primitives.values here.]] |
| |
| The second function call (the one with no arguments) calls the nullary function |
| which then returns `3`. The need for a second function call is the reason why |
| the function is said to be [*/Lazily Evaluated/]. The first call doesn't do |
| anything. You need a second call to finally evaluate the thing. The first call |
| lazily evaluates the function; i.e. doesn't do anything and defers the evaluation |
| for later. |
| |
| [h2 Callbacks] |
| |
| It may not be immediately apparent how lazy evaluation can be useful by just |
| looking at the example above. Putting the first and second function call in a |
| single line is really not very useful. However, thinking of `val(3)` as a |
| callback function (and in most cases they are actually used that way), will make |
| it clear. Example: |
| |
| template <typename F> |
| void print(F f) |
| { |
| cout << f() << endl; |
| } |
| |
| int |
| main() |
| { |
| print(val(3)); |
| print(val("Hello World")); |
| return 0; |
| } |
| |
| (See [@../../example/users_manual/callback.cpp callback.cpp]) |
| |
| [endsect] |
| [section References] |
| |
| References are functions. They hold a reference to a value stored somewhere. |
| For example, given: |
| |
| int i = 3; |
| char const* s = "Hello World"; |
| |
| we create `references` to `i` and `s` this way: |
| |
| ref(i) |
| ref(s) |
| |
| Like `val`, the expressions above evaluates to a nullary function; the first one |
| returning an `int&`, and the second one returning a `char const*&`. |
| |
| (See [@../../example/users_manual/references.cpp references.cpp]) |
| |
| [blurb __tip__ Learn more about references [link phoenix.primitives.references here.]] |
| |
| [endsect] |
| [section Arguments] |
| |
| Arguments are also functions? You bet! |
| |
| Until now, we have been dealing with expressions returning a nullary function. |
| Arguments, on the other hand, evaluate to an N-ary function. An argument |
| represents the Nth argument. There are a few predefined arguments arg1, |
| arg2, arg3, arg4 and so on (and it's __bll__ counterparts: _1, _2, _3, _4 and so |
| on). Examples: |
| |
| arg1 // one-or-more argument function that returns its first argument |
| arg2 // two-or-more argument function that returns its second argument |
| arg3 // three-or-more argument function that returns its third argument |
| |
| `argN` returns the Nth argument. Examples: |
| |
| int i = 3; |
| char const* s = "Hello World"; |
| cout << arg1(i) << endl; // prints 3 |
| cout << arg2(i, s) << endl; // prints "Hello World" |
| |
| (See [@../../example/users_manual/arguments.cpp arguments.cpp]) |
| |
| [blurb __tip__ Learn more about arguments [link phoenix.primitives.arguments here.]] |
| |
| [endsect] |
| [section Composites] |
| |
| What we have seen so far, are what are called *primitives*. You can think of |
| primitives (such as values, references and arguments) as atoms. |
| |
| Things start to get interesting when we start /composing/ primitives to form |
| *composites*. The composites can, in turn, be composed to form even more complex |
| composites. |
| |
| [endsect] |
| [section Lazy Operators] |
| |
| You can use the usual set of operators to form composites. Examples: |
| |
| arg1 * arg1 |
| ref(x) = arg1 + ref(z) |
| arg1 = arg2 + (3 * arg3) |
| ref(x) = arg1[arg2] // assuming arg1 is indexable and arg2 is a valid index |
| |
| Note the expression: `3 * arg3`. This expression is actually a short-hand |
| equivalent to: `val(3) * arg3`. In most cases, like above, you can get away with |
| it. But in some cases, you will have to explicitly wrap your values in `val`. |
| Rules of thumb: |
| |
| * In a binary expression (e.g. `3 * arg3`), at least one of the operands must be |
| a phoenix primitive or composite. |
| * In a unary expression (e.g. `arg1++`), the single operand must be a phoenix |
| primitive or composite. |
| |
| If these basic rules are not followed, the result is either in error, or is |
| immediately evaluated. Some examples: |
| |
| ref(x) = 123 // lazy |
| x = 123 // immediate |
| |
| ref(x)[0] // lazy |
| x[0] // immediate |
| |
| ref(x)[ref(i)] // lazy |
| ref(x)[i] // lazy (equivalent to ref(x)[val(i)]) |
| x[ref(i)] // illegal (x is not a phoenix primitive or composite) |
| ref(x[ref(i)]) // illegal (x is not a phoenix primitive or composite) |
| |
| [blurb __tip__ Learn more about operators [link phoenix.composite.operator here.]] |
| |
| [h2 First Practical Example] |
| |
| We've covered enough ground to present a real world example. We want to find the |
| first odd number in an STL container. Normally we use a functor (function |
| object) or a function pointer and pass that in to STL's `find_if` generic |
| function: |
| |
| Write a function: |
| |
| bool |
| is_odd(int arg1) |
| { |
| return arg1 % 2 == 1; |
| } |
| |
| Pass a pointer to the function to STL's `find_if` algorithm: |
| |
| find_if(c.begin(), c.end(), &is_odd) |
| |
| Using Phoenix, the same can be achieved directly with a one-liner: |
| |
| find_if(c.begin(), c.end(), arg1 % 2 == 1) |
| |
| The expression `arg1 % 2 == 1` auto-magically creates a functor with the expected |
| behavior. In FP, this unnamed function is called a lambda function. Unlike the |
| function pointer version, which is monomorphic (expects and works only with a |
| fixed type int argument), the Phoenix version is fully polymorphic and works |
| with any container (of ints, of longs, of bignum, etc.) as long as its elements |
| can handle the `arg1 % 2 == 1` expression. |
| |
| (See [@../../example/users_manual/find_if.cpp find_if.cpp]) |
| |
| [blurb __tip__ ...[*That's it, we're done]. Well if you wish to know a little bit |
| more, read on...] |
| |
| [endsect] |
| [section Lazy Statements] |
| |
| Lazy statements? Sure. There are lazy versions of the C++ statements we all know |
| and love. For example: |
| |
| if_(arg1 > 5) |
| cout << arg1 |
| |
| Say, for example, we wish to print all the elements that are greater than 5 |
| (separated by a comma) in a vector. Here's how we write it: |
| |
| for_each(v.begin(), v.end(), |
| if_(arg1 > 5) |
| [ |
| cout << arg1 << ", " |
| ] |
| ); |
| |
| (See [@../../example/users_manual/if.cpp if.cpp]) |
| |
| [blurb __tip__ Learn more about statements [link phoenix.composite.statement here.]] |
| |
| [endsect] |
| [section Construct, New, Delete, Casts] |
| |
| You'll probably want to work with objects. There are lazy versions of |
| constructor calls, `new`, `delete` and the suite of C++ casts. Examples: |
| |
| construct<std::string>(arg1, arg2) // constructs a std::string from arg1, arg2 |
| new_<std::string>(arg1, arg2) // makes a new std::string from arg1, arg2 |
| delete_(arg1) // deletes arg1 (assumed to be a pointer) |
| static_cast_<int*>(arg1) // static_cast's arg1 to an int* |
| |
| [note Take note that, by convention, names that conflict with C++ |
| reserved words are appended with a single trailing underscore `'_'`] |
| |
| [blurb __tip__ Learn more about this [link phoenix.composite.object here.]] |
| |
| [endsect] |
| [section Lazy Functions] |
| |
| As you write more lambda functions, you'll notice certain patterns that you wish |
| to refactor as reusable functions. When you reach that point, you'll wish that |
| ordinary functions can co-exist with phoenix functions. Unfortunately, the |
| /immediate/ nature of plain C++ functions make them incompatible. |
| |
| Lazy functions are your friends. The library provides a facility to make lazy |
| functions. The code below is a rewrite of the `is_odd` function using the |
| facility: |
| |
| struct is_odd_impl |
| { |
| template <typename Arg> |
| struct result |
| { |
| typedef bool type; |
| }; |
| |
| template <typename Arg> |
| bool operator()(Arg arg1) const |
| { |
| return arg1 % 2 == 1; |
| } |
| }; |
| |
| function<is_odd_impl> is_odd; |
| |
| [h2 Things to note:] |
| |
| * `result` is a nested metafunction that reflects the return type of the |
| function (in this case, bool). This makes the function fully polymorphic: |
| It can work with arbitrary `Arg` types. |
| * There are as many Args in the `result` metafunction as in the actual |
| `operator()`. |
| * `is_odd_impl` implements the function. |
| * `is_odd`, an instance of `function<is_odd_impl>`, is the lazy function. |
| |
| Now, `is_odd` is a truly lazy function that we can use in conjunction with the |
| rest of phoenix. Example: |
| |
| find_if(c.begin(), c.end(), is_odd(arg1)); |
| |
| (See [@../../example/users_manual/function.cpp function.cpp]) |
| |
| [h2 Predefined Lazy Functions] |
| |
| The library is chock full of STL savvy, predefined lazy functions covering the |
| whole of the STL containers, iterators and algorithms. For example, there are lazy |
| versions of container related operations such as assign, at, back, begin, |
| pop_back, pop_front, push_back, push_front, etc. (See [link phoenix.container |
| Container]). |
| |
| [endsect] |
| [section More] |
| |
| As mentioned earlier, this chapter is not a thorough discourse of the library. |
| It is meant only to cover enough ground to get you into high gear as quickly as |
| possible. Some advanced stuff is not discussed here (e.g. [link phoenix.composite.scope |
| Scopes]); nor are features that provide alternative (short-hand) ways to do the |
| same things (e.g. [link phoenix.composite.bind Bind] vs. Lazy Functions). |
| |
| [blurb __tip__ ...*If you still wish to learn more, the read on...*] |
| |
| [endsect] |
| [endsect] |
| |
| [section Basics] |
| |
| [def __constant_n__ /n/] |
| [def __argument_n__ a/n/] |
| |
| Almost everything is a function in the Phoenix library that can be evaluated as |
| `f(a1, a2, ..., __argument_n__)`, where __constant_n__ is the function's arity, or number of arguments that the |
| function expects. Operators are also functions. For example, `a + b` is just a |
| function with arity == 2 (or binary). `a + b` is the same as `add(a, b)`, `a + b |
| + c` is the same as `add(add(a, b), c)`. |
| |
| [note Amusingly, functions may even return functions. We shall see |
| what this means in a short while.] |
| |
| [h2 Partial Function Application] |
| |
| Think of a function as a black box. You pass arguments and it returns something |
| back. The figure below depicts the typical scenario. |
| |
| [$images/fbox.png] |
| |
| A fully evaluated function is one in which all the arguments are given. All |
| functions in plain C++ are fully evaluated. When you call the `sin(x)` function, |
| you have to pass a number x. The function will return a result in return: the |
| sin of x. When you call the `add(x, y)` function, you have to pass two numbers x |
| and y. The function will return the sum of the two numbers. The figure below is |
| a fully evaluated `add` function. |
| |
| [$images/adder.png] |
| |
| A partially applied function, on the other hand, is one in which not all the |
| arguments are supplied. If we are able to partially apply the function `add` |
| above, we may pass only the first argument. In doing so, the function does not |
| have all the required information it needs to perform its task to compute and |
| return a result. What it returns instead is another function, a lambda function |
| --another black box. Unlike the original `add` function which has an arity of 2, |
| the resulting lambda function has an arity of 1. Why? because we already |
| supplied part of the input: `2` |
| |
| [$images/add2.png] |
| |
| Now, when we shove in a number into our lambda function, it will return 2 plus |
| whatever we pass in. The lambda function essentially remembers 1) the original |
| function, `add`, and 2) the partial input, 2. The figure below illustrates a |
| case where we pass 3 to our lambda function, which then returns 5: |
| |
| [$images/add2_call.png] |
| |
| Obviously, partially applying the `add` function, as we see above, cannot be |
| done directly in C++ where we are expected to supply all the arguments that a |
| function expects. That's where the Phoenix library comes in. The library |
| provides the facilities to do partial function application. |
| |
| [h2 STL and higher order functions] |
| |
| So, what's all the fuss? What makes partial function application so useful? |
| Recall our original example in the [link phoenix.starter_kit previous section]: |
| |
| find_if(c.begin(), c.end(), arg1 % 2 == 1) |
| |
| The expression `arg1 % 2 == 1` evaluates to a lambda function. `arg1` is a placeholder |
| for an argument to be supplied later. Hence, since there's only one unsupplied argument, the |
| lambda function has an arity 1. It just so happens that `find_if` supplies the |
| unsupplied argument as it loops from `c.begin()` to `c.end()`. |
| |
| [note Higher order functions are functions which can take other |
| functions as arguments, and may also return functions as results. Higher order |
| functions are functions that are treated like any other objects and can be used as |
| arguments and return values from functions.] |
| |
| [h2 Lazy Evaluation] |
| |
| In Phoenix, to put it more accurately, function evaluation has two stages: |
| |
| # Partial application |
| # Final evaluation |
| |
| The first stage is handled by a set of generator functions. These are your front |
| ends (in the client's perspective). These generators create (through partial |
| function application), higher order functions that can be passed on just like |
| any other function pointer or function object. The second stage, the actual |
| function call, can be invoked or executed anytime in the future, or not at all; |
| hence /"lazy"/. |
| |
| If we look more closely, the first step involves partial function application: |
| |
| arg1 % 2 == 1 |
| |
| The second step is the actual function invocation (done inside the `find_if` |
| function. These are the back-ends (often, the final invocation is never actually |
| seen by the client). In our example, the `find_if`, if we take a look inside, |
| we'll see something like: |
| |
| template <class InputIterator, class Predicate> |
| InputIterator |
| find_if(InputIterator first, InputIterator last, Predicate pred) |
| { |
| while (first != last && !pred(*first)) // <--- The lambda function is called here |
| ++first; // passing in *first |
| return first; |
| } |
| |
| Again, typically, we, as clients, see only the first step. However, in this |
| document and in the examples and tests provided, don't be surprised to see the |
| first and second steps juxtaposed in order to illustrate the complete semantics |
| of Phoenix expressions. Examples: |
| |
| int x = 1; |
| int y = 2; |
| |
| cout << (arg1 % 2 == 1)(x) << endl; // prints 1 or true |
| cout << (arg1 % 2 == 1)(y) << endl; // prints 0 or false |
| |
| |
| [h2 Forwarding Function Problem] |
| |
| Usually, we, as clients, write the call-back functions while libraries (such as |
| STL) provide the callee (e.g. `find_if`). In case the role is reversed, e.g. |
| if you have to write an STL algorithm that takes in a predicate, or develop a |
| GUI library that accepts event handlers, you have to be aware of a little known |
| problem in C++ called the "__forwarding__". |
| |
| Look again at the code above: |
| |
| (arg1 % 2 == 1)(x) |
| |
| Notice that, in the second-stage (the final evaluation), we used a variable `x`. |
| Be aware that the second stage cannot accept non-const temporaries and literal |
| constants. Hence, this will fail: |
| |
| (arg1 % 2 == 1)(123) // Error! |
| |
| Disallowing non-const rvalues partially solves the "__forwarding__" but |
| prohibits code like above. |
| |
| [h2 Polymorphic Functions] |
| |
| Unless otherwise noted, Phoenix generated functions are fully polymorphic. For |
| instance, the `add` example above can apply to integers, floating points, user |
| defined complex numbers or even strings. Example: |
| |
| std::string h("Hello"); |
| char const* w = " World"; |
| std::string r = add(arg1, arg2)(h, w); |
| |
| evaluates to `std::string("Hello World")`. The observant reader might notice |
| that this function call in fact takes in heterogeneous arguments where `arg1` is |
| of type `std::string` and `arg2` is of type `char const*`. `add` still works |
| because the C++ standard library allows the expression `a + b` where `a` is a |
| `std::string` and `b` is a `char const*`. |
| |
| [endsect] |
| |
| [section Organization] |
| |
| Care and attention to detail was given, painstakingly, to the design and |
| implementation of Phoenix. |
| |
| The library is organized in four layers: |
| |
| [$images/organization.png] |
| |
| The modules are orthogonal, with no cyclic dependencies. |
| Lower layers do not depend on higher layers. Modules in a layer do not depend on other modules in the same layer. |
| This means, for example, that Bind can be completely discarded if it is |
| not required; or one could perhaps take out Operator and Statement and just use Function, |
| which may be desirable in a pure FP application. |
| |
| The library has grown from the original Phoenix but still comprises only |
| header files. There are no object files to link against. |
| |
| [h2 Core] |
| |
| The lowest two layers comprise the core. |
| |
| The `Actor` is the main concept behind the library. Lazy functions are |
| abstracted as actors. There are only 2 |
| kinds of actors: |
| |
| # Primitives |
| # Composites |
| |
| Primitives provide the basic building blocks of functionality within Phoenix. |
| Composites are used to combine these primitives together to provide more |
| powerful functionality. |
| |
| Composites are composed of zero or more actors. Each actor in a composite can |
| again be another composite. |
| |
| [table Modules |
| [[Module] [Description]] |
| [[Function] [Lazy functions support (e.g. `add`)]] |
| [[Operator] [Lazy operators support (e.g. `+`)]] |
| [[Statement] [Lazy statments (e.g. `if_`, `while_`)]] |
| [[Object] [Lazy casts (e.g. `static_cast_`), |
| object creation destruction (e.g. |
| `new_`, `delete_`)]] |
| [[Scope] [Support for scopes, local variables and lambda-lambda]] |
| [[Bind] [Lazy functions from free functions, member functions or member variables.]] |
| [[Container] [Set of predefined "lazy" functions that work on STL |
| containers and sequences (e.g. `push_back`).]] |
| [[Algorithm] [Set of predefined "lazy" versions of the STL algorithms |
| (e.g. `find_if`).]] |
| ] |
| |
| Each module is defined in a header file with the same name. For example, |
| the core module is defined in `<boost/spirit/home/phoenix/core.hpp>`. |
| |
| [table Includes |
| [[Module] [File]] |
| [[Core] [`#include <boost/spirit/home/phoenix/core.hpp>`]] |
| [[Function] [`#include <boost/spirit/home/phoenix/function.hpp>`]] |
| [[Operator] [`#include <boost/spirit/home/phoenix/operator.hpp>`]] |
| [[Statement] [`#include <boost/spirit/home/phoenix/statement.hpp>`]] |
| [[Object] [`#include <boost/spirit/home/phoenix/object.hpp>`]] |
| [[Scope] [`#include <boost/spirit/home/phoenix/scope.hpp>`]] |
| [[Bind] [`#include <boost/spirit/home/phoenix/bind.hpp>`]] |
| [[Container] [`#include <boost/spirit/home/phoenix/container.hpp>`]] |
| [[Algorithm] [`#include <boost/spirit/home/phoenix/algorithm.hpp>`]] |
| ] |
| |
| [blurb __tip__ Finer grained include files are available per feature; see the |
| succeeding sections.] |
| |
| [endsect] |
| |
| [section Actors] |
| |
| The `Actor` is the main concept behind the library. Actors are function objects. |
| An actor can accept 0 to `PHOENIX_LIMIT` arguments. |
| |
| [note You can set `PHOENIX_LIMIT`, the predefined maximum arity an |
| actor can take. By default, `PHOENIX_LIMIT` is set to 10.] |
| |
| Phoenix supplies an `actor` class template whose specializations |
| model the `Actor` concept. `actor` has one template parameter, `Eval`, |
| that supplies the smarts to evaluate the resulting function. |
| |
| template <typename Eval> |
| struct actor : Eval |
| { |
| return_type |
| operator()() const; |
| |
| template <typename T0> |
| return_type |
| operator()(T0& _0) const; |
| |
| template <typename T0, typename T1> |
| return_type |
| operator()(T0& _0, T1& _1) const; |
| |
| //... |
| }; |
| |
| The actor class accepts the arguments through a set of function call operators |
| for 0 to `PHOENIX_LIMIT` arities (Don't worry about the details, for now. Note, for example, |
| that we skimp over the details regarding `return_type`). The arguments |
| are then forwarded to the actor's `Eval` for evaluation. |
| |
| [endsect] |
| |
| [section Primitives] |
| |
| Actors are composed to create more complex actors in a tree-like hierarchy. The |
| primitives are atomic entities that are like the leaves in the tree. Phoenix is |
| extensible. New primitives can be added anytime. Right out of the box, there are |
| only a few primitives. This section shall deal with these preset primitives. |
| |
| [section Arguments] |
| |
| #include <boost/spirit/home/phoenix/core/argument.hpp> |
| |
| We use an instance of: |
| |
| actor<argument<N> > |
| |
| to represent the Nth function argument. The argument placeholder acts as an |
| imaginary data-bin where a function argument will be placed. |
| |
| [h2 Predefined Arguments] |
| |
| There are a few predefined instances of `actor<argument<N> >` named |
| `arg1`..`argN`, and its __bll__ counterpart `_1`..`_N`. (where N is a predefined |
| maximum). |
| |
| Here are some sample preset definitions of `arg1`..`argN` |
| |
| actor<argument<0> > const arg1 = argument<0>(); |
| actor<argument<1> > const arg2 = argument<1>(); |
| actor<argument<2> > const arg3 = argument<2>(); |
| |
| and its __bll__ `_1`..`_N` style counterparts: |
| |
| actor<argument<0> > const _1 = argument<0>(); |
| actor<argument<1> > const _2 = argument<1>(); |
| actor<argument<2> > const _3 = argument<2>(); |
| |
| [note You can set `PHOENIX_ARG_LIMIT`, the predefined maximum |
| placeholder index. By default, `PHOENIX_ARG_LIMIT` is set to `PHOENIX_LIMIT` |
| (See [link phoenix.actors Actors]).] |
| |
| [h2 User Defined Arguments] |
| |
| When appropriate, you can define your own `argument<N>` names. For example: |
| |
| actor<argument<0> > x; // note zero based index |
| |
| `x` may now be used as a parameter to a lazy function: |
| |
| add(x, 6) |
| |
| which is equivalent to: |
| |
| add(arg1, 6) |
| |
| [h2 Evaluating an Argument] |
| |
| An argument, when evaluated, selects the Nth argument from the those passed |
| in by the client. |
| |
| For example: |
| |
| char c = 'A'; |
| int i = 123; |
| const char* s = "Hello World"; |
| |
| cout << arg1(c) << endl; // Get the 1st argument: c |
| cout << arg1(i, s) << endl; // Get the 1st argument: i |
| cout << arg2(i, s) << endl; // Get the 2nd argument: s |
| |
| will print out: |
| |
| A |
| 123 |
| Hello World |
| |
| [h2 Extra Arguments] |
| |
| In C and C++, a function can have extra arguments that are not at all used by |
| the function body itself. These extra arguments are simply ignored. |
| |
| Phoenix also allows extra arguments to be passed. For example, recall our |
| original `add` function: |
| |
| add(arg1, arg2) |
| |
| We know now that partially applying this function results to a function that |
| expects 2 arguments. However, the library is a bit more lenient and allows the |
| caller to supply more arguments than is actually required. Thus, `add` actually |
| allows 2 /or more/ arguments. For instance, with: |
| |
| add(arg1, arg2)(x, y, z) |
| |
| the third argument `z` is ignored. Taking this further, in-between arguments are |
| also ignored. Example: |
| |
| add(arg1, arg5)(a, b, c, d, e) |
| |
| Here, arguments b, c, and d are ignored. The function `add` takes in the first |
| argument (`arg1`) and the fifth argument (`arg5`). |
| |
| [note There are a few reasons why enforcing strict arity is not |
| desirable. A case in point is the callback function. Typical callback functions |
| provide more information than is actually needed. Lambda functions are often |
| used as callbacks.] |
| |
| [endsect] |
| |
| [section Values] |
| |
| #include <boost/spirit/home/phoenix/core/value.hpp> |
| |
| Whenever we see a constant in a partially applied function, an |
| |
| actor<value<T> > |
| |
| (where T is the type of the constant) is automatically created for |
| us. For instance: |
| |
| add(arg1, 6) |
| |
| Passing a second argument, `6`, an `actor<value<int> >` is implicitly created |
| behind the scenes. This is also equivalent to: |
| |
| add(arg1, val(6)) |
| |
| `val(x)` generates an `actor<value<T> >` where `T` is the type of `x`. In most |
| cases, there's no need to explicitly use `val`, but, as we'll see later on, |
| there are situations where this is unavoidable. |
| |
| [h2 Evaluating a Value] |
| |
| Like arguments, values are also actors. As such, values can be evaluated. |
| Invoking a value gives the value's identity. Example: |
| |
| cout << val(3)() << val("Hello World")(); |
| |
| prints out "3 Hello World". |
| |
| [endsect] |
| |
| [section References] |
| |
| #include <boost/spirit/home/phoenix/core/reference.hpp> |
| |
| Values are immutable constants. Attempting to modify a value will result in a |
| compile time error. When we want the function to modify the parameter, we use a |
| reference instead. For instance, imagine a lazy function `add_assign`: |
| |
| void add_assign(T& x, T y) { x += y; } // pseudo code |
| |
| Here, we want the first function argument, x, to be mutable. Obviously, we |
| cannot write: |
| |
| add_assign(1, 2) // error first argument is immutable |
| |
| In C++, we can pass in a reference to a variable as the first argument in our |
| example above. Yet, by default, the library forces arguments passed to partially |
| applied functions functions to be immutable values (see [link phoenix.primitives.values |
| Values]). To achieve our intent, we use: |
| |
| actor<reference<T> > |
| |
| This is similar to `actor<value<T> >` above but instead holds a reference to a |
| variable. |
| |
| We normally don't instantiate `actor<reference<T> >` objects directly. Instead we |
| use `ref`. For example (where `i` is an `int` variable): |
| |
| add_assign(ref(i), 2) |
| |
| [h2 Evaluating a Reference] |
| |
| References are actors. Hence, references can be evaluated. Such invocation gives |
| the reference's identity. Example: |
| |
| int i = 3; |
| char const* s = "Hello World"; |
| cout << ref(i)() << ref(s)(); |
| |
| prints out "3 Hello World" |
| |
| [endsect] |
| [section Constant References] |
| |
| #include <boost/spirit/home/phoenix/core/reference.hpp> |
| |
| Another free function `cref(cv)` may also be used. `cref(cv)` creates an |
| `actor<reference<T const&> >` object. This is similar to `actor<value<T> >` but |
| when the data to be passed as argument to a function is heavy and expensive to |
| copy by value, the `cref(cv)` offers a lighter alternative. |
| |
| [endsect] |
| [section Nothing] |
| |
| #include <boost/spirit/home/phoenix/core/nothing.hpp> |
| |
| Finally, the `actor<null_actor>` does nothing; (a "bum", if you will :-). |
| There's a sole `actor<null_actor>` instance named "nothing". This actor is |
| actually useful in situations where we don't want to do anything. (See |
| [link phoenix.composite.statement.for__statement for_ Statement] for example). |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section Composite] |
| |
| Actors may be combined in a multitude of ways to form composites. Composites are |
| actors that are composed of zero or more actors. Composition is hierarchical. An |
| element of the composite can be a primitive or again another composite. The |
| flexibility to arbitrarily compose hierarchical structures allows us to form |
| intricate constructions that model complex functions, statements and |
| expressions. |
| |
| A composite is-a tuple of 0..N actors. N is the predefined maximum actors a |
| composite can take. |
| |
| [note You can set `PHOENIX_COMPOSITE_LIMIT`, the predefined maximum |
| actors a composite can take. By default, `PHOENIX_COMPOSITE_LIMIT` is set to |
| `PHOENIX_LIMIT` (See [link phoenix.actors Actors]).] |
| |
| As mentioned, each of the actors A0..AN can, in turn, be another composite, |
| since a composite is itself an actor. This makes the composite a recursive |
| structure. The actual evaluation is handled by a composite specific eval policy. |
| |
| [section Function] |
| |
| #include <boost/spirit/home/phoenix/function/function.hpp> |
| |
| The `function` class template provides a mechanism for implementing lazily |
| evaluated functions. Syntactically, a lazy function looks like an ordinary C/C++ function. |
| The function call looks familiar and feels the same as ordinary C++ functions. |
| However, unlike ordinary functions, the actual function execution is deferred. |
| |
| Unlike ordinary function pointers or functor objects that need to be explicitly bound through the bind function (see [link phoenix.composite.bind Bind]), |
| the argument types of these functions are automatically lazily bound. |
| |
| In order to create a lazy function, we need to implement a model of the |
| FunctionEval concept. For a function that takes `N` arguments, a model of FunctionEval must |
| provide: |
| |
| * An `operator()` that implements that takes `N` arguments, and implements |
| the function logic. |
| * A nested metafunction `result<A1, ... AN>` that takes the types of the `N` arguments to |
| the function and returns the result type of the function. (There is a special case for function |
| objects that accept no arguments. Such nullary functors are only required to define a typedef |
| `result_type` that reflects the return type of its `operator()`). |
| |
| For example, the following type implements the FunctionEval concept, in order to provide a |
| lazy factorial function: |
| |
| struct factorial_impl |
| { |
| template <typename Arg> |
| struct result |
| { |
| typedef Arg type; |
| }; |
| |
| template <typename Arg> |
| Arg operator()(Arg n) const |
| { |
| return (n <= 0) ? 1 : n * this->operator()(n-1); |
| } |
| }; |
| |
| (See [@../../example/users_manual/factorial.cpp factorial.cpp]) |
| |
| Having implemented the `factorial_impl` type, we can declare and instantiate a lazy |
| `factorial` function this way: |
| |
| function<factorial_impl> factorial; |
| |
| Invoking a lazy function such as `factorial` does not immediately execute the function |
| object `factorial_impl`. Instead, an [link phoenix.actors actor] object is |
| created and returned to the caller. Example: |
| |
| factorial(arg1) |
| |
| does nothing more than return an actor. A second function call will invoke |
| the actual factorial function. Example: |
| |
| int i = 4; |
| cout << factorial(arg1)(i); |
| |
| will print out "24". |
| |
| Take note that in certain cases (e.g. for function objects with state), an |
| instance of the model of FunctionEval may be passed on to the constructor. Example: |
| |
| function<factorial_impl> factorial(ftor); |
| |
| where ftor is an instance of factorial_impl (this is not necessary in this case |
| as `factorial_impl` does not require any state). |
| |
| [blurb __alert__ Take care though when using function objects with state because they are |
| often copied repeatedly, and state may change in one of the copies, rather than the |
| original.] |
| |
| [endsect] |
| |
| [section Operator] |
| |
| This facility provides a mechanism for lazily evaluating operators. |
| Syntactically, a lazy operator looks and feels like an ordinary C/C++ infix, |
| prefix or postfix operator. The operator application looks the same. However, |
| unlike ordinary operators, the actual operator execution is deferred. Samples: |
| |
| arg1 + arg2 |
| 1 + arg1 * arg2 |
| 1 / -arg1 |
| arg1 < 150 |
| |
| We have seen the lazy operators in action (see [link phoenix.starter_kit |
| Quick Start]). Let's go back and examine them a little bit further: |
| |
| find_if(c.begin(), c.end(), arg1 % 2 == 1) |
| |
| Through operator overloading, the expression `arg1 % 2 == 1` actually generates |
| an actor. This actor object is passed on to STL's `find_if` function. From |
| the viewpoint of STL, the composite is simply a function object expecting a |
| single argument of the containers value_type. For each element in `c`, |
| the element is passed on as an argument `arg1` to the actor (function |
| object). The actor checks if this is an odd value based on the expression |
| `arg1 % 2 == 1` where arg1 is replaced by the container's element. |
| |
| Like lazy functions (see |
| [link phoenix.composite.function function]), lazy operators are not immediately executed |
| when invoked. Instead, an actor (see [link phoenix.actors actors]) |
| object is created and returned to the caller. Example: |
| |
| (arg1 + arg2) * arg3 |
| |
| does nothing more than return an actor. A second function call will evaluate |
| the actual operators. Example: |
| |
| int i = 4, j = 5, k = 6; |
| cout << ((arg1 + arg2) * arg3)(i, j, k); |
| |
| will print out "54". |
| |
| Operator expressions are lazily evaluated following four simple rules: |
| |
| # A binary operator, except `->*` will be lazily evaluated when |
| /at least/ one of its operands is an actor object |
| (see [link phoenix.actors actors]). |
| # Unary operators are lazily evaluated if their argument is an actor object. |
| # Operator `->*` is lazily evaluated if the left hand argument is an actor object. |
| # The result of a lazy operator is an actor object that can in turn allow the |
| applications of rules 1 and 2. |
| |
| For example, to check the following expression is lazily evaluated: |
| |
| -(arg1 + 3 + 6) |
| |
| # Following rule 1, `arg1 + 3` is lazily evaluated since `arg1` is an actor |
| (see [link phoenix.primitives primitives]). |
| # The result of this `arg1 + 3` expression is an actor object, following rule 4. |
| # Continuing, `arg1 + 3 + 6` is again lazily evaluated. |
| Rule 2. |
| # By rule 4 again, the result of `arg1 + 3 + 6` is an actor object. |
| # As `arg1 + 3 + 6` is an actor, `-(arg1 + 3 + 6)` is lazily evaluated. Rule 2. |
| |
| Lazy-operator application is highly contagious. In most cases, a single `argN` |
| actor infects all its immediate neighbors within a group (first level or |
| parenthesized expression). |
| |
| Note that at least one operand of any operator must be a valid actor |
| for lazy evaluation to take effect. To force lazy evaluation of an |
| ordinary expression, we can use `ref(x)`, `val(x)` or `cref(x)` to |
| transform an operand into a valid actor object (see [link phoenix.primitives primitives]. |
| For example: |
| |
| 1 << 3; // Immediately evaluated |
| val(1) << 3; // Lazily evaluated |
| |
| [h2 Supported operators] |
| |
| [h3 Unary operators] |
| |
| prefix: ~, !, -, +, ++, --, & (reference), * (dereference) |
| postfix: ++, -- |
| |
| [h3 Binary operators] |
| |
| =, [], +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= |
| +, -, *, /, %, &, |, ^, <<, >> |
| ==, !=, <, >, <=, >= |
| &&, ||, ->* |
| |
| [h3 Ternary operator] |
| |
| if_else(c, a, b) |
| |
| The ternary operator deserves special mention. Since C++ does not allow us to |
| overload the conditional expression: `c ? a : b`, the if_else pseudo function is |
| provided for this purpose. The behavior is identical, albeit in a lazy manner. |
| |
| [h3 Member pointer operator] |
| |
| a->*member_object_pointer |
| a->*member_function_pointer |
| |
| The left hand side of the member pointer operator must be an actor returning a pointer |
| type. The right hand side of the member pointer operator may be either a pointer to member |
| object or pointer to member function. |
| |
| If the right hand side is a member object pointer, the result is an actor which, when evaluated, |
| returns a reference to that member. For example: |
| |
| struct A |
| { |
| int member; |
| }; |
| |
| A* a = new A; |
| ... |
| |
| (arg1->*&A::member)(a); // returns member a->member |
| |
| If the right hand side is a member function pointer, the result is an actor which, when invoked, calls the specified member function. For example: |
| |
| struct A |
| { |
| int func(int); |
| }; |
| |
| A* a = new A; |
| int i = 0; |
| |
| (arg1->*&A::func)(arg2)(a, i); // returns a->func(i) |
| |
| [table Include Files |
| [[Operators] [File]] |
| [[`-`, `+`, `++`, `--`, `+=`, |
| `-=`, `*=`, `/=`, `%=`, |
| `*`, `/`, `%`] [`#include <boost/spirit/home/phoenix/operator/arithmetic.hpp>`]] |
| [[`&=`, `|=`, `^=`, `<<=`, |
| `>>=`, `&`, `|`, `^`, `<<`, |
| `>>`] [`#include <boost/spirit/home/phoenix/operator/bitwise.hpp>`]] |
| [[`==`, `!=`, `<`, |
| `<=`, `>`, `>=`] [`#include <boost/spirit/home/phoenix/operator/comparison.hpp>`]] |
| [[`<<`, `>>`] [`#include <boost/spirit/home/phoenix/operator/io.hpp>`]] |
| [[`!`, &&, `||`] [`#include <boost/spirit/home/phoenix/operator/logical.hpp>`]] |
| [[`&x`, `*p`, `=`, `[]`] [`#include <boost/spirit/home/phoenix/operator/self.hpp>`]] |
| [[`if_else(c, a, b)`] [`#include <boost/spirit/home/phoenix/operator/if_else.hpp>`]] |
| [[`->*`] [`#include <boost/spirit/home/phoenix/operator/member.hpp>`]] |
| ] |
| |
| [endsect] |
| |
| [section Statement] |
| |
| [*/Lazy statements.../] |
| |
| The primitives and composite building blocks presented so far are sufficiently |
| powerful to construct quite elaborate structures. We have presented lazy- |
| functions and lazy-operators. How about lazy-statements? First, an appetizer: |
| |
| Print all odd-numbered contents of an STL container using `std::for_each` |
| ([@../../example/users_manual/all_odds.cpp all_odds.cpp]): |
| |
| for_each(c.begin(), c.end(), |
| if_(arg1 % 2 == 1) |
| [ |
| cout << arg1 << ' ' |
| ] |
| ); |
| |
| Huh? Is that valid C++? Read on... |
| |
| Yes, it is valid C++. The sample code above is as close as you can get to the |
| syntax of C++. This stylized C++ syntax differs from actual C++ code. First, the |
| `if` has a trailing underscore. Second, the block uses square brackets instead |
| of the familiar curly braces {}. |
| |
| [note *C++ in C++?* |
| |
| In as much as __spirit__ attempts to mimic EBNF in C++, |
| Phoenix attempts to mimic C++ in C++!!! |
| ] |
| |
| Here are more examples with annotations. The code almost speaks for itself. |
| |
| [section Block Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/sequence.hpp> |
| |
| Syntax: |
| |
| statement, |
| statement, |
| .... |
| statement |
| |
| Basically, these are comma separated statements. Take note that unlike the C/C++ |
| semicolon, the comma is a separator put *in-between* statements. This is like |
| Pascal's semicolon separator, rather than C/C++'s semicolon terminator. For |
| example: |
| |
| statement, |
| statement, |
| statement, // ERROR! |
| |
| Is an error. The last statement should not have a comma. Block statements can be |
| grouped using the parentheses. Again, the last statement in a group should not |
| have a trailing comma. |
| |
| statement, |
| statement, |
| ( |
| statement, |
| statement |
| ), |
| statement |
| |
| Outside the square brackets, block statements should be grouped. For example: |
| |
| for_each(c.begin(), c.end(), |
| ( |
| do_this(arg1), |
| do_that(arg1) |
| ) |
| ); |
| |
| Wrapping a comma operator chain around a parentheses pair blocks the |
| interpretation as an argument separator. The reason for the exception for |
| the square bracket operator is that the operator always takes exactly one |
| argument, so it "transforms" any attempt at multiple arguments with a comma |
| operator chain (and spits out an error for zero arguments). |
| |
| [endsect] |
| [section if_ Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/if.hpp> |
| |
| We have seen the `if_` statement. The syntax is: |
| |
| if_(conditional_expression) |
| [ |
| sequenced_statements |
| ] |
| |
| [endsect] |
| [section if\_else\_ statement] |
| |
| #include <boost/spirit/home/phoenix/statement/if.hpp> |
| |
| The syntax is |
| |
| if_(conditional_expression) |
| [ |
| sequenced_statements |
| ] |
| .else_ |
| [ |
| sequenced_statements |
| ] |
| |
| Take note that `else` has a leading dot and a trailing underscore: `.else_` |
| |
| Example: This code prints out all the elements and appends `" > 5"`, `" == 5"` |
| or `" < 5"` depending on the element's actual value: |
| |
| for_each(c.begin(), c.end(), |
| if_(arg1 > 5) |
| [ |
| cout << arg1 << " > 5\n" |
| ] |
| .else_ |
| [ |
| if_(arg1 == 5) |
| [ |
| cout << arg1 << " == 5\n" |
| ] |
| .else_ |
| [ |
| cout << arg1 << " < 5\n" |
| ] |
| ] |
| ); |
| |
| Notice how the `if_else_` statement is nested. |
| |
| [endsect] |
| [section switch_ statement] |
| |
| #include <boost/spirit/home/phoenix/statement/switch.hpp> |
| |
| The syntax is: |
| |
| switch_(integral_expression) |
| [ |
| case_<integral_value>(sequenced_statements), |
| ... |
| default_<integral_value>(sequenced_statements) |
| ] |
| |
| A comma separated list of cases, and an optional default can be provided. Note unlike |
| a normal switch statement, cases do not fall through. |
| |
| Example: This code prints out `"one"`, `"two"` or `"other value"` depending on the |
| element's actual value: |
| |
| for_each(c.begin(), c.end(), |
| switch_(arg1) |
| [ |
| case_<1>(cout << val("one") << '\n'), |
| case_<2>(cout << val("two") << '\n'), |
| default_(cout << val("other value") << '\n') |
| ] |
| ); |
| |
| [endsect] |
| [section while_ Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/while.hpp> |
| |
| The syntax is: |
| |
| while_(conditional_expression) |
| [ |
| sequenced_statements |
| ] |
| |
| Example: This code decrements each element until it reaches zero and prints out |
| the number at each step. A newline terminates the printout of each value. |
| |
| for_each(c.begin(), c.end(), |
| ( |
| while_(arg1--) |
| [ |
| cout << arg1 << ", " |
| ], |
| cout << val("\n") |
| ) |
| ); |
| |
| [endsect] |
| [section do\_while\_ Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/do_while.hpp> |
| |
| The syntax is: |
| |
| do_ |
| [ |
| sequenced_statements |
| ] |
| .while_(conditional_expression) |
| |
| Again, take note that `while` has a leading dot and a trailing underscore: |
| `.while_` |
| |
| Example: This code is almost the same as the previous example above with a |
| slight twist in logic. |
| |
| for_each(c.begin(), c.end(), |
| ( |
| do_ |
| [ |
| cout << arg1 << ", " |
| ] |
| .while_(arg1--), |
| cout << val("\n") |
| ) |
| ); |
| |
| [endsect] |
| [section for_ Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/for.hpp> |
| |
| The syntax is: |
| |
| for_(init_statement, conditional_expression, step_statement) |
| [ |
| sequenced_statements |
| ] |
| |
| It is again very similar to the C++ for statement. Take note that the |
| init\_statement, conditional\_expression and step\_statement are separated by the |
| comma instead of the semi-colon and each must be present (i.e. `for_(,,)` is |
| invalid). This is a case where the [link phoenix.primitives.nothing nothing] |
| actor can be useful. |
| |
| Example: This code prints each element N times where N is the element's value. A |
| newline terminates the printout of each value. |
| |
| int iii; |
| for_each(c.begin(), c.end(), |
| ( |
| for_(ref(iii) = 0, ref(iii) < arg1, ++ref(iii)) |
| [ |
| cout << arg1 << ", " |
| ], |
| cout << val("\n") |
| ) |
| ); |
| |
| As before, all these are lazily evaluated. The result of such statements are in |
| fact composites that are passed on to STL's for_each function. In the viewpoint |
| of `for_each`, what was passed is just a functor, no more, no less. |
| |
| [note Unlike lazy functions and lazy operators, lazy statements always |
| return void.] |
| |
| [endsect] |
| [section try_ catch_ Statement] |
| |
| #include <boost/spirit/home/phoenix/statement/try_catch.hpp> |
| |
| The syntax is: |
| |
| try_ |
| [ |
| sequenced_statements |
| ] |
| .catch_<exception_type>() |
| [ |
| sequenced_statements |
| ] |
| ... |
| .catch_all |
| [ |
| sequenced_statement |
| ] |
| |
| Note the usual underscore after try and catch, and the extra parentheses required |
| after the catch. |
| |
| Example: The following code calls the (lazy) function `f` for each element, and |
| prints messages about different exception types it catches. |
| |
| try_ |
| [ |
| f(arg1) |
| ] |
| .catch_<runtime_error>() |
| [ |
| cout << val("caught runtime error or derived\n") |
| ] |
| .catch_<exception>() |
| [ |
| cout << val("caught exception or derived\n") |
| ] |
| .catch_all |
| [ |
| cout << val("caught some other type of exception\n") |
| ] |
| |
| [endsect] |
| [section throw_] |
| |
| #include <boost/spirit/home/phoenix/statement/throw.hpp> |
| |
| As a natural companion to the try/catch support, the statement module provides |
| lazy throwing and rethrowing of exceptions. |
| |
| The syntax to throw an exception is: |
| |
| throw_(exception_expression) |
| |
| The syntax to rethrow an exception is: |
| |
| throw_() |
| |
| Example: This code extends the try/catch example, rethrowing exceptions derived from |
| runtime_error or exception, and translating other exception types to runtime_errors. |
| |
| try_ |
| [ |
| f(arg1) |
| ] |
| .catch_<runtime_error>() |
| [ |
| cout << val("caught runtime error or derived\n"), |
| throw_() |
| ] |
| .catch_<exception>() |
| [ |
| cout << val("caught exception or derived\n"), |
| throw_() |
| ] |
| .catch_all |
| [ |
| cout << val("caught some other type of exception\n"), |
| throw_(runtime_error("translated exception")) |
| ] |
| |
| [endsect] |
| [endsect] |
| |
| [section Object] |
| |
| The Object module deals with object construction, destruction and conversion. |
| The module provides /"lazy"/ versions of C++'s object constructor, `new`, |
| `delete`, `static_cast`, `dynamic_cast`, `const_cast` and `reinterpret_cast`. |
| |
| [h2 Construction] |
| |
| [*/Lazy constructors.../] |
| |
| #include <boost/spirit/home/phoenix/object/construct.hpp> |
| |
| Lazily construct an object from an arbitrary set of arguments: |
| |
| construct<T>(ctor_arg1, ctor_arg2, ..., ctor_argN); |
| |
| where the given parameters are the parameters to the constructor of the object of |
| type T (This implies, that type T is expected to have a constructor with a |
| corresponding set of parameter types.). |
| |
| Example: |
| |
| construct<std::string>(arg1, arg2) |
| |
| Constructs a `std::string` from `arg1` and `arg2`. |
| |
| [note The maximum number of actual parameters is limited by the |
| preprocessor constant PHOENIX_COMPOSITE_LIMIT. Note though, that this limit |
| should not be greater than PHOENIX_LIMIT. By default, `PHOENIX_COMPOSITE_LIMIT` |
| is set to `PHOENIX_LIMIT` (See [link phoenix.actors Actors]).] |
| |
| [h2 New] |
| |
| [*/Lazy new.../] |
| |
| #include <boost/spirit/home/phoenix/object/new.hpp> |
| |
| Lazily construct an object, on the heap, from an arbitrary set of arguments: |
| |
| new_<T>(ctor_arg1, ctor_arg2, ..., ctor_argN); |
| |
| where the given parameters are the parameters to the constructor of the object of |
| type T (This implies, that type T is expected to have a constructor with a |
| corresponding set of parameter types.). |
| |
| Example: |
| |
| new_<std::string>(arg1, arg2) // note the spelling of new_ (with trailing underscore) |
| |
| Creates a `std::string` from `arg1` and `arg2` on the heap. |
| |
| [note Again, the maximum number of actual parameters is limited by the |
| preprocessor constant PHOENIX_COMPOSITE_LIMIT. See the note above.] |
| |
| [h2 Delete] |
| |
| [*/Lazy delete.../] |
| |
| #include <boost/spirit/home/phoenix/object/delete.hpp> |
| |
| Lazily delete an object, from the heap: |
| |
| delete_(arg); |
| |
| where arg is assumed to be a pointer to an object. |
| |
| Example: |
| |
| delete_<std::string>(arg1) // note the spelling of delete_ (with trailing underscore) |
| |
| [h2 Casts] |
| |
| [*/Lazy casts.../] |
| |
| #include <boost/spirit/home/phoenix/object/static_cast.hpp> |
| #include <boost/spirit/home/phoenix/object/dynamic_cast.hpp> |
| #include <boost/spirit/home/phoenix/object/const_cast.hpp> |
| #include <boost/spirit/home/phoenix/object/reinterpret_cast.hpp> |
| |
| The set of lazy C++ cast template functions provide a way of lazily casting an |
| object of a certain type to another type. The syntax resembles the well known |
| C++ casts. Take note however that the lazy versions have a trailing underscore. |
| |
| static_cast_<T>(lambda_expression) |
| dynamic_cast_<T>(lambda_expression) |
| const_cast_<T>(lambda_expression) |
| reinterpret_cast_<T>(lambda_expression) |
| |
| Example: |
| |
| static_cast_<Base*>(&arg1) |
| |
| Static-casts the address of `arg1` to a `Base*`. |
| |
| [endsect] |
| |
| [section Scope] |
| |
| Up until now, the most basic ingredient is missing: creation of and access to |
| local variables in the stack. When recursion comes into play, you will soon |
| realize the need to have true local variables. It may seem that we do not need |
| this at all since an unnamed lambda function cannot call itself anyway; at least |
| not directly. With some sort of arrangement, situations will arise where a |
| lambda function becomes recursive. A typical situation occurs when we store a |
| lambda function in a [@http://www.boost.org/libs/function Boost.Function], |
| essentially naming the unnamed lambda. |
| |
| There will also be situations where a lambda function gets passed as an argument |
| to another function. This is a more common situation. In this case, the lambda |
| function assumes a new scope; new arguments and possibly new local variables. |
| |
| This section deals with local variables and nested lambda scopes. |
| |
| [h2 Local Variables] |
| |
| #include <boost/spirit/home/phoenix/scope/local_variable.hpp> |
| |
| We use an instance of: |
| |
| actor<local_variable<Key> > |
| |
| to represent a local variable. The local variable acts as an imaginary data-bin |
| where a local, stack based data will be placed. `Key` is an arbitrary type that |
| is used to identify the local variable. Example: |
| |
| struct size_key; |
| actor<local_variable<size_key> > size; |
| |
| [h2 Predefined Local Variables] |
| |
| There are a few predefined instances of `actor<local_variable<Key> >` |
| named `_a`..`_z` that you can already use. To make use of them, simply use the |
| `namespace boost::phoenix::local_names`: |
| |
| using namespace boost::phoenix::local_names; |
| |
| [h2 let] |
| |
| #include <boost/spirit/home/phoenix/scope/let.hpp> |
| |
| You declare local variables using the syntax: |
| |
| let(local-declarations) |
| [ |
| let-body |
| ] |
| |
| `let` allows 1..N local variable declarations (where N == |
| `PHOENIX_LOCAL_LIMIT`). Each declaration follows the form: |
| |
| local-id = lambda-expression |
| |
| [note You can set `PHOENIX_LOCAL_LIMIT`, the predefined maximum local |
| variable declarations in a let expression. By default, `PHOENIX_LOCAL_LIMIT` is |
| set to `PHOENIX_LIMIT`.] |
| |
| Example: |
| |
| let(_a = 123, _b = 456) |
| [ |
| _a + _b |
| ] |
| |
| [h2 Reference Preservation] |
| |
| The type of the local variable assumes the type of the lambda- expression. Type |
| deduction is reference preserving. For example: |
| |
| let(_a = arg1, _b = 456) |
| |
| `_a` assumes the type of `arg1`: a reference to an argument, while `_b` has type |
| `int`. |
| |
| Consider this: |
| |
| int i = 1; |
| |
| let(_a = arg1) |
| [ |
| cout << --_a << ' ' |
| ] |
| (i); |
| |
| cout << i << endl; |
| |
| the output of above is : 0 0 |
| |
| While with this: |
| |
| int i = 1; |
| |
| let(_a = val(arg1)) |
| [ |
| cout << --_a << ' ' |
| ] |
| (i); |
| |
| cout << i << endl; |
| |
| the output is : 0 1 |
| |
| Reference preservation is necessary because we need to have L-value access to |
| outer lambda-scopes (especially the arguments). `arg`s and `ref`s are L-values. |
| `val`s are R-values. |
| |
| [h2 Visibility] |
| |
| The scope and lifetimes of the local variables is limited within the let-body. |
| `let` blocks can be nested. A local variable may hide an outer local variable. |
| For example: |
| |
| let(_x = 1, _y = ", World") |
| [ |
| // _x here is an int: 1 |
| |
| let(_x = "Hello") // hides the outer _x |
| [ |
| cout << _x << _y // prints "Hello, World" |
| ] |
| ] |
| |
| The RHS (right hand side lambda-expression) of each local-declaration cannot |
| refer to any LHS local-id. At this point, the local-ids are not in scope yet; |
| they will only be in scope in the let-body. The code below is in error: |
| |
| let( |
| _a = 1 |
| , _b = _a // Error: _a is not in scope yet |
| ) |
| [ |
| // _a and _b's scope starts here |
| /*. body .*/ |
| ] |
| |
| However, if an outer let scope is available, this will be searched. Since |
| the scope of the RHS of a local-declaration is the outer scope enclosing |
| the let, the RHS of a local-declaration can refer to a local variable of |
| an outer scope: |
| |
| let(_a = 1) |
| [ |
| let( |
| _a = 1 |
| , _b = _a // Ok. _a refers to the outer _a |
| ) |
| [ |
| /*. body .*/ |
| ] |
| ] |
| |
| [h2 lambda] |
| |
| #include <boost/spirit/home/phoenix/scope/lambda.hpp> |
| |
| A lot of times, you'd want to write a lazy function that accepts one or more |
| functions (higher order functions). STL algorithms come to mind, for example. |
| Consider a lazy version of `stl::for_each`: |
| |
| struct for_each_impl |
| { |
| template <typename C, typename F> |
| struct result |
| { |
| typedef void type; |
| }; |
| |
| template <typename C, typename F> |
| void operator()(C& c, F f) const |
| { |
| std::for_each(c.begin(), c.end(), f); |
| } |
| }; |
| |
| function<for_each_impl> const for_each = for_each_impl(); |
| |
| Notice that the function accepts another function, `f` as an argument. The scope |
| of this function, `f`, is limited within the `operator()`. When `f` is called |
| inside `std::for_each`, it exists in a new scope, along with new arguments and, |
| possibly, local variables. This new scope is not at all related to the outer |
| scopes beyond the `operator()`. |
| |
| Simple syntax: |
| |
| lambda |
| [ |
| lambda-body |
| ] |
| |
| Like `let`, local variables may be declared, allowing 1..N local variable |
| declarations (where N == `PHOENIX_LOCAL_LIMIT`): |
| |
| lambda(local-declarations) |
| [ |
| lambda-body |
| ] |
| |
| The same restrictions apply with regard to scope and visibility. The RHS |
| (right hand side lambda-expression) of each local-declaration cannot refer |
| to any LHS local-id. The local-ids are not in scope yet; they will be in |
| scope only in the lambda-body: |
| |
| lambda( |
| _a = 1 |
| , _b = _a // Error: _a is not in scope yet |
| ) |
| |
| See [link phoenix.composite.scope.visibility `let` Visibility] above for more information. |
| |
| Example: Using our lazy `for_each` let's print all the elements in a container: |
| |
| for_each(arg1, lambda[cout << arg1]) |
| |
| As far as the arguments are concerned (arg1..argN), the scope in which the |
| lambda-body exists is totally new. The left `arg1` refers to the argument passed |
| to `for_each` (a container). The right `arg1` refers to the argument passed by |
| `std::for_each` when we finally get to call `operator()` in our `for_each_impl` |
| above (a container element). |
| |
| Yet, we may wish to get information from outer scopes. While we do not have |
| access to arguments in outer scopes, what we still have is access to local |
| variables from outer scopes. We may only be able to pass argument related |
| information from outer `lambda` scopes through the local variables. |
| |
| [note This is a crucial difference between `let` and `lambda`: `let` |
| does not introduce new arguments; `lambda` does.] |
| |
| Another example: Using our lazy `for_each`, and a lazy `push_back`: |
| |
| struct push_back_impl |
| { |
| template <typename C, typename T> |
| struct result |
| { |
| typedef void type; |
| }; |
| |
| template <typename C, typename T> |
| void operator()(C& c, T& x) const |
| { |
| c.push_back(x); |
| } |
| }; |
| |
| function<push_back_impl> const push_back = push_back_impl(); |
| |
| write a lambda expression that accepts: |
| |
| # a 2-dimensional container (e.g. `vector<vector<int> >`) |
| # a container element (e.g. `int`) |
| |
| and pushes-back the element to each of the `vector<int>`. |
| |
| Solution: |
| |
| for_each(arg1, |
| lambda(_a = arg2) |
| [ |
| push_back(arg1, _a) |
| ] |
| ) |
| |
| Since we do not have access to the arguments of the outer scopes beyond the |
| lambda-body, we introduce a local variable `_a` that captures the second outer |
| argument: `arg2`. Hence: _a = arg2. This local variable is visible inside the |
| lambda scope. |
| |
| (See [@../../example/users_manual/lambda.cpp lambda.cpp]) |
| |
| [endsect] |
| |
| [section Bind] |
| |
| ['Binding] is the act of tying together a function to some arguments for |
| deferred (lazy) evaluation. Named [link phoenix.composite.function Lazy functions] |
| require a bit of typing. Unlike (unnamed) lambda expressions, we need to write a |
| functor somewhere off-line, detached from the call site. If you wish to transform a |
| plain function, member function or member variable to a lambda expression, `bind` |
| is your friend. |
| |
| [note Take note that binders are monomorphic. Rather than binding |
| functions, the preferred way is to write true generic and polymorphic [link |
| phoenix.composite.function lazy-functions]. However, since most of the time we |
| are dealing with adaptation of existing code, binders get the job done faster.] |
| |
| There is a set of overloaded `bind` template functions. Each `bind(x)` |
| function generates a suitable binder object, a [link phoenix.composite |
| composite]. |
| |
| [h2 Binding Functions] |
| |
| #include <boost/spirit/home/phoenix/bind/bind_function.hpp> |
| |
| Example, given a function `foo`: |
| |
| void foo(int n) |
| { |
| std::cout << n << std::endl; |
| } |
| |
| Here's how the function `foo` may be bound: |
| |
| bind(&foo, arg1) |
| |
| This is now a full-fledged [link phoenix.composite composite] that can finally |
| be evaluated by another function call invocation. A second function call will |
| invoke the actual `foo` function. Example: |
| |
| int i = 4; |
| bind(&foo, arg1)(i); |
| |
| will print out "4". |
| |
| [h2 Binding Member Functions] |
| |
| #include <boost/spirit/home/phoenix/bind/bind_member_function.hpp> |
| |
| Binding member functions can be done similarly. A bound member function takes in |
| a pointer or reference to an object as the first argument. For instance, given: |
| |
| struct xyz |
| { |
| void foo(int) const; |
| }; |
| |
| `xyz`'s `foo` member function can be bound as: |
| |
| bind(&xyz::foo, obj, arg1) // obj is an xyz object |
| |
| Take note that a lazy-member functions expects the first argument to be a |
| pointer or reference to an object. Both the object (reference or pointer) and |
| the arguments can be lazily bound. Examples: |
| |
| xyz obj; |
| bind(&xyz::foo, arg1, arg2) // arg1.foo(arg2) |
| bind(&xyz::foo, obj, arg1) // obj.foo(arg1) |
| bind(&xyz::foo, obj, 100) // obj.foo(100) |
| |
| [h2 Binding Member Variables] |
| |
| #include <boost/spirit/home/phoenix/bind/bind_member_variable.hpp> |
| |
| Member variables can also be bound much like member functions. Member variables |
| are not functions. Yet, like the [link phoenix.primitives.references `ref(x)`] that |
| acts like a nullary function returning a reference to the data, member variables, |
| when bound, act like a unary function, taking in a pointer or reference to an |
| object as its argument and returning a reference to the bound member variable. |
| For instance, given: |
| |
| struct xyz |
| { |
| int v; |
| }; |
| |
| `xyz::v` can be bound as: |
| |
| bind(&xyz::v, obj) // obj is an xyz object |
| |
| As noted, just like the bound member function, a bound member variable also |
| expects the first (and only) argument to be a pointer or reference to an object. |
| The object (reference or pointer) can be lazily bound. Examples: |
| |
| xyz obj; |
| bind(&xyz::v, arg1) // arg1.v |
| bind(&xyz::v, obj) // obj.v |
| bind(&xyz::v, arg1)(obj) = 4 // obj.v = 4 |
| |
| [endsect] |
| |
| [endsect] |
| [section Container] |
| |
| #include <boost/spirit/home/phoenix/container.hpp> |
| |
| The container module predefines a set of lazy functions that work on STL |
| containers. These functions provide a mechanism for the lazy evaluation of the |
| public member functions of the STL containers. The lazy functions are thin |
| wrappers that simply forward to their respective counterparts in the STL |
| library. |
| |
| Lazy functions are provided for all of the member functions of the following |
| containers: |
| |
| * deque |
| * list |
| * map |
| * multimap |
| * vector |
| |
| Indeed, should your class have member functions with the same names and |
| signatures as those listed below, then it will automatically be supported. To |
| summarize, lazy functions are provided for member functions: |
| |
| * assign |
| * at |
| * back |
| * begin |
| * capacity |
| * clear |
| * empty |
| * end |
| * erase |
| * front |
| * get_allocator |
| * insert |
| * key_comp |
| * max_size |
| * pop_back |
| * pop_front |
| * push_back |
| * push_front |
| * rbegin |
| * rend |
| * reserve |
| * resize |
| * size |
| * splice |
| * value_comp |
| |
| The lazy functions' names are the same as the corresponding member function. The |
| difference is that the lazy functions are free functions and therefore does not |
| use the member "dot" syntax. |
| |
| [table Sample usage |
| [["Normal" version] ["Lazy" version]] |
| [[`my_vector.at(5)`] [`at(arg1, 5)`]] |
| [[`my_list.size()`] [`size(arg1)`]] |
| [[`my_vector1.swap(my_vector2)`] [`swap(arg1, arg2)`]] |
| ] |
| |
| Notice that member functions with names that clash with stl algorithms are |
| absent. This will be provided in Phoenix's algorithm module. |
| |
| No support is provided here for lazy versions of `operator+=`, `operator[]` etc. |
| Such operators are not specific to STL containers and lazy versions can |
| therefore be found in [link phoenix.composite.operator operators]. |
| |
| The following table describes the container functions and their semantics. |
| |
| [blurb __tip__ Arguments in brackets denote optional parameters.] |
| |
| [table Lazy STL Container Functions |
| [[Function] [Semantics]] |
| [[`assign(c, a[, b, c])`] [`c.assign(a[, b, c])`]] |
| [[`at(c, i)`] [`c.at(i)`]] |
| [[`back(c)`] [`c.back()`]] |
| [[`begin(c)`] [`c.begin()`]] |
| [[`capacity(c)`] [`c.capacity()`]] |
| [[`clear(c)`] [`c.clear()`]] |
| [[`empty(c)`] [`c.empty()`]] |
| [[`end(c)`] [`c.end()`]] |
| [[`erase(c, a[, b])`] [`c.erase(a[, b])`]] |
| [[`front(c)`] [`c.front()`]] |
| [[`get_allocator(c)`] [`c.get_allocator()`]] |
| [[`insert(c, a[, b, c])`] [`c.insert(a[, b, c])`]] |
| [[`key_comp(c)`] [`c.key_comp()`]] |
| [[`max_size(c)`] [`c.max_size()`]] |
| [[`pop_back(c)`] [`c.pop_back()`]] |
| [[`pop_front(c)`] [`c.pop_front()`]] |
| [[`push_back(c, d)`] [`c.push_back(d)`]] |
| [[`push_front(c, d)`] [`c.push_front(d)`]] |
| [[`pop_front(c)`] [`c.pop_front()`]] |
| [[`rbegin(c)`] [`c.rbegin()`]] |
| [[`rend(c)`] [`c.rend()`]] |
| [[`reserve(c, n)`] [`c.reserve(n)`]] |
| [[`resize(c, a[, b])`] [`c.resize(a[, b])`]] |
| [[`size(c)`] [`c.size()`]] |
| [[`splice(c, a[, b, c, d])`] [`c.splice(a[, b, c, d])`]] |
| [[`value_comp(c)`] [`c.value_comp()`]] |
| ] |
| |
| [endsect] |
| |
| [section Algorithm] |
| |
| #include <boost/spirit/home/phoenix/algorithm.hpp> |
| |
| The algorithm module provides wrappers for the standard algorithms in the |
| `<algorithm>` and `<numeric>` headers. |
| |
| The algorithms are divided into the categories iteration, transformation and querying, |
| modelling the __boost_mpl__ library. The different algorithm classes can be |
| included using the headers: |
| |
| #include <boost/spirit/home/phoenix/stl/algorithm/iteration.hpp> |
| #include <boost/spirit/home/phoenix/stl/algorithm/transformation.hpp> |
| #include <boost/spirit/home/phoenix/stl/algorithm/querying.hpp> |
| |
| The functions of the algorithm module take ranges as arguments where |
| appropriate. This is different to the standard |
| library, but easy enough to pick up. Ranges are described in detail in the |
| __boost_range__ library. |
| |
| For example, using the standard copy algorithm to copy between 2 arrays: |
| |
| int array[] = {1, 2, 3}; |
| int output[3]; |
| std::copy(array, array + 3, output); // We have to provide iterators |
| // to both the start and end of array |
| |
| The analogous code using the phoenix algorithm module is: |
| |
| int array[] = {1, 2, 3}; |
| int output[3]; |
| copy(arg1, arg2)(array, output); // Notice only 2 arguments, the end of |
| // array is established automatically |
| |
| The __boost_range__ library provides support for standard containers, strings and |
| arrays, and can be extended to support additional types. |
| |
| The following tables describe the different categories of algorithms, and their |
| semantics. |
| |
| [blurb __tip__ Arguments in brackets denote optional parameters.] |
| |
| [table Iteration Algorithms |
| [[Function] [stl Semantics]] |
| [[`for_each(r, c)`] [`for_each(begin(r), end(r), f)`]] |
| [[`accumulate(r, o[, f])`] [`accumulate(begin(r), end(r), o[, f])`]] |
| ] |
| |
| [table Querying Algorithms |
| [[Function] [stl Semantics]] |
| [[`find(r, a)`] [`find(begin(r), end(r), a)`]] |
| [[`find_if(r, f)`] [`find_if(begin(r), end(r), f)`]] |
| [[`find_end(r1, r2[, f])`] [`find_end(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`find_first_of(r1, r2[, f])`] [`find_first_of(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`adjacent_find(r[, f])`] [`adjacent_find(begin(r), end(r)[, f])`]] |
| [[`count(r, a)`] [`count(begin(r), end(r), a)`]] |
| [[`count_if(r, f)`] [`count_if(begin(r), end(r), f)`]] |
| [[`distance(r)`] [`distance(begin(r), end(r))`]] |
| [[`mismatch(r, i[, f])`] [`mismatch(begin(r), end(r), i[, f])`]] |
| [[`equal(r, i[, f])`] [`equal(begin(r), end(r), i[, f])`]] |
| [[`search(r1, r2[, f])`] [`search(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`lower_bound(r, a[, f])`] [`lower_bound(begin(r), end(r), a[, f])`]] |
| [[`upper_bound(r, a[, f])`] [`upper_bound(begin(r), end(r), a[, f])`]] |
| [[`equal_range(r, a[, f])`] [`equal_range(begin(r), end(r), a[, f])`]] |
| [[`binary_search(r, a[, f])`] [`binary_search(begin(r), end(r), a[, f])`]] |
| [[`includes(r1, r2[, f])`] [`includes(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`min_element(r[, f])`] [`min_element(begin(r), end(r)[, f])`]] |
| [[`max_element(r[, f])`] [`max_element(begin(r), end(r)[, f])`]] |
| [[`lexicographical_compare(r1, r2[, f])`] [`lexicographical_compare(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| ] |
| |
| [table Transformation Algorithms |
| [[Function] [stl Semantics]] |
| [[`copy(r, o)`] [`copy(begin(r), end(r), o)`]] |
| [[`copy_backward(r, o)`] [`copy_backward(begin(r), end(r), o)`]] |
| [[`transform(r, o, f)`] [`transform(begin(r), end(r), o, f)`]] |
| [[`transform(r, i, o, f)`] [`transform(begin(r), end(r), i, o, f)`]] |
| [[`replace(r, a, b)`] [`replace(begin(r), end(r), a, b)`]] |
| [[`replace_if(r, f, a)`] [`replace(begin(r), end(r), f, a)`]] |
| [[`replace_copy(r, o, a, b)`] [`replace_copy(begin(r), end(r), o, a, b)`]] |
| [[`replace_copy_if(r, o, f, a)`] [`replace_copy_if(begin(r), end(r), o, f, a)`]] |
| [[`fill(r, a)`] [`fill(begin(r), end(r), a)`]] |
| [[`fill_n(r, n, a)`] [`fill_n(begin(r), n, a)`]] |
| [[`generate(r, f)`] [`generate(begin(r), end(r), f)`]] |
| [[`generate_n(r, n, f)`] [`generate_n(begin(r), n, f)`]] |
| [[`remove(r, a)`] [`remove(begin(r), end(r), a)`]] |
| [[`remove_if(r, f)`] [`remove_if(begin(r), end(r), f)`]] |
| [[`remove_copy(r, o, a)`] [`remove_copy(begin(r), end(r), o, a)`]] |
| [[`remove_copy_if(r, o, f)`] [`remove_copy_if(begin(r), end(r), o, f)`]] |
| [[`unique(r[, f])`] [`unique(begin(r), end(r)[, f])`]] |
| [[`unique_copy(r, o[, f])`] [`unique_copy(begin(r), end(r), o[, f])`]] |
| [[`reverse(r)`] [`reverse(begin(r), end(r))`]] |
| [[`reverse_copy(r, o)`] [`reverse_copy(begin(r), end(r), o)`]] |
| [[`rotate(r, m)`] [`rotate(begin(r), m, end(r))`]] |
| [[`rotate_copy(r, m, o)`] [`rotate_copy(begin(r), m, end(r), o)`]] |
| [[`random_shuffle(r[, f])`] [`random_shuffle(begin(r), end(r), f)`]] |
| [[`partition(r, f)`] [`partition(begin(r), end(r), f)`]] |
| [[`stable_partition(r, f)`] [`stable_partition(begin(r), end(r), f)`]] |
| [[`sort(r[, f])`] [`sort(begin(r), end(r)[, f])`]] |
| [[`stable_sort(r[, f])`] [`stable_sort(begin(r), end(r)[, f])`]] |
| [[`partial_sort(r, m[, f])`] [`partial_sort(begin(r), m, end(r)[, f])`]] |
| [[`partial_sort_copy(r1, r2[, f])`] [`partial_sort_copy(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`nth_element(r, n[, f])`] [`nth_element(begin(r), n, end(r)[, f])`]] |
| [[`merge(r1, r2, o[, f])`] [`merge(begin(r1), end(r1), begin(r2), end(r2), o[, f])`]] |
| [[`inplace_merge(r, m[, f])`] [`inplace_merge(begin(r), m, end(r)[, f])`]] |
| [[`set_union(r1, r2, o[, f])`] [`set_union(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`set_intersection(r1, r2, o[, f])`] [`set_intersection(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`set_difference(r1, r2, o[, f])`] [`set_difference(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`set_symmetric_difference(r1, r2, o[, f])`] [`set_symmetric_difference(begin(r1), end(r1), begin(r2), end(r2)[, f])`]] |
| [[`push_heap(r[, f])`] [`push_heap(begin(r), end(r)[, f])`]] |
| [[`pop_heap(r[, f])`] [`pop_heap(begin(r), end(r)[, f])`]] |
| [[`make_heap(r[, f])`] [`make_heap(begin(r), end(r)[, f])`]] |
| [[`sort_heap(r[, f])`] [`sort_heap(begin(r), end(r)[, f])`]] |
| [[`next_permutation(r[, f])`] [`next_permutation(begin(r), end(r)[, f])`]] |
| [[`prev_permutation(r[, f])`] [`prev_permutation(begin(r), end(r)[, f])`]] |
| |
| [[`inner_product(r, o, a[, f1, f2])`] [`inner_product(begin(r), end(r), o[, f1, f2])`]] |
| [[`partial_sum(r, o[, f])`] [`partial_sum(begin(r), end(r), o[, f])`]] |
| [[`adjacent_difference(r, o[, f])`] [`adjacent_difference(begin(r), end(r), o[, f])`]] |
| ] |
| |
| [endsect] |
| |
| [section Inside Phoenix] |
| |
| [def __eval_policy__ [link phoenix.inside_phoenix.composites_in_detail.evalpolicy `EvalPolicy`]] |
| [def __eval__ [link phoenix.inside_phoenix.actors_in_detail.eval_concept `Eval`]] |
| [def __eval_tuple__ [link phoenix.inside_phoenix.composites_in_detail.evaltuple `EvalTuple`]] |
| [def __environment__ [link phoenix.inside_phoenix.actors_in_detail.environment `Environment`]] |
| |
| This chapter explains in more detail how the library operates. The information |
| henceforth should not be necessary to those who are interested in just using the |
| library. However, a microscopic view might prove to be beneficial to moderate |
| to advanced programmers who wish to extend the library. |
| |
| [section Actors In Detail] |
| |
| [h3 Actor Concept] |
| |
| The main concept is the `Actor`. Actors are function objects (that can accept 0 |
| to N arguments (where N is a predefined maximum). |
| |
| [note You can set `PHOENIX_LIMIT`, the predefined maximum arity an |
| actor can take. By default, `PHOENIX_LIMIT` is set to 10.] |
| |
| [h3 actor template class] |
| |
| The `actor` template class models the `Actor` concept: |
| |
| template <typename Eval> |
| struct actor : Eval |
| { |
| typedef Eval eval_type; |
| |
| actor(); |
| actor(Eval const& base); |
| |
| template <typename T0> |
| explicit actor(T0 const& _0); |
| |
| template <typename T0, typename T1> |
| actor(T0 const& _0, T1 const& _1); |
| |
| // more constructors |
| |
| typename apply_actor<eval_type, basic_environment<> >::type |
| operator()() const; |
| |
| template <typename T0> |
| typename apply_actor<eval_type, basic_environment<T0> >::type |
| operator()(T0& _0) const; |
| |
| template <typename T0, typename T1> |
| typename apply_actor<eval_type, basic_environment<T0, T1> >::type |
| operator()(T0& _0, T1& _1) const; |
| |
| // function call operators |
| }; |
| |
| [table Actor Concept Requirements |
| [ [Expression] [Result/Semantics] ] |
| [ [`T::eval_type`] [The actor's Eval type] ] |
| [ [`T()`] [Default Constructor] ] |
| [ [`T(base)`] [Constructor from Eval] ] |
| [ [`T(arg0, arg1, ..., argN)`] [Pass through constructors] ] |
| [ [`x(arg0, arg1, ..., argN)`] [Function call operators] ] |
| ] |
| |
| [h3 Eval Concept] |
| |
| The `actor` template class has a single template parameter, `Eval`, from which |
| it derives from. While the `Actor` concept represents a function, the `Eval` |
| concept represents the function body. The requirements for `Eval` are |
| intentionally kept simple, to make it easy to write models of the concept. We |
| shall see an example in the [link phoenix.inside_phoenix.actor_example next section]. |
| |
| [table Eval Concept Requirements |
| [ [Expression] [Result/Semantics] ] |
| [ [`return x.eval(env)`] [Evaluates the function (see Environment below)] ] |
| [ [`T::result<Env>::type`] [The return type of eval (see Environment below)] ] |
| ] |
| |
| [h3 Constructors] |
| |
| In addition to a default constructor and an constructor from a Eval object, |
| there are templated (pass through) constructors for 1 to N arguments (N == |
| `PHOENIX_LIMIT`). These constructors simply forward the arguments to the `base`. |
| |
| [note *Parametric Base Class Pattern* |
| |
| Notice that actor derives from its template argument Eval. This is the |
| inverse of the curiously recurring template pattern (CRTP). With the CRTP, a |
| class, T, has a Derived template parameter that is assumed to be its |
| subclass. The "parametric base class pattern" (PBCP), on the other hand, |
| inverses the inheritance and makes a class, T, the derived class. Both CRTP |
| and PBCP techniques have its pros and cons, which is outside the scope of |
| this document. CRTP should really be renamed "parametric subclass pattern |
| (PSCP), but again, that's another story. |
| ] |
| |
| [h3 Function Call Operators] |
| |
| There are N function call operators for 0 to N arguments (N == `PHOENIX_LIMIT`). |
| The actor class accepts the arguments and forwards the arguments to the actor's |
| base `Eval` for evaluation. |
| |
| [def [$http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm] |
| |
| [note *Forwarding Function Problem* |
| |
| The function call operators cannot accept non-const temporaries and literal |
| constants. There is a known issue with current C++ called the |
| "__forwarding__". The problem is that given an arbitrary function `F`, using |
| current C++ language rules, one cannot create a forwarding function `FF` |
| that transparently assumes the arguments of `F`. Disallowing non-const |
| rvalues arguments partially solves the problem but prohibits code such as |
| `f(1, 2, 3);`. |
| ] |
| |
| [h3 Environment] |
| |
| On an actor function call, before calling the actor's `Eval::eval` for |
| evaluation, the actor creates an ['*environment*]. Basically, the environment |
| packages the arguments in a tuple. The `Environment` is a concept, of which, the |
| `basic_environment` template class is a model of. |
| |
| [table Environment Concept Requirements |
| [ [Expression] [Result/Semantics] ] |
| [ [`x.args()`] [The arguments in a tie (a tuple of references)] ] |
| [ [`T::args_type`] [The arguments' types in an MPL sequence] ] |
| [ [`T::tie_type`] [The tie (tuple of references) type] ] |
| ] |
| |
| Schematically: |
| |
| [$images/funnel_in.png] |
| |
| Other parts of the library (e.g. the scope module) extends the `Environment` |
| concept to hold other information such as local variables, etc. |
| |
| [h3 apply_actor] |
| |
| `apply_actor` is a standard MPL style metafunction that simply calls the |
| Action's `result` nested metafunction: |
| |
| template <typename Action, typename Env> |
| struct apply_actor |
| { |
| typedef typename Action::template result<Env>::type type; |
| }; |
| |
| After evaluating the arguments and doing some computation, the `eval` member |
| function returns something back to the client. To do this, the forwarding |
| function (the actor's `operator()`) needs to know the return type of the eval |
| member function that it is calling. For this purpose, models of `Eval` are |
| required to provide a nested template class: |
| |
| template <typename Env> |
| struct result; |
| |
| This nested class provides the result type information returned by the `Eval`'s |
| `eval` member function. The nested template class `result` should have a typedef |
| `type` that reflects the return type of its member function `eval`. |
| |
| For reference, here's a typical `actor::operator()` that accepts two arguments: |
| |
| template <typename T0, typename T1> |
| typename apply_actor<eval_type, basic_environment<T0, T1> >::type |
| operator()(T0& _0, T1& _1) const |
| { |
| return eval_type::eval(basic_environment<T0, T1>(_0, _1)); |
| } |
| |
| [h3 actor_result] |
| |
| For reasons of symmetry to the family of `actor::operator()` there is a special |
| metafunction usable for actor result type calculation named `actor_result`. This |
| metafunction allows us to directly to specify the types of the parameters to be |
| passed to the `actor::operator()` function. Here's a typical `actor_result` that |
| accepts two arguments: |
| |
| template <typename Action, typename T0, typename T1> |
| struct actor_result |
| { |
| typedef basic_environment<T0, T1> env_type; |
| typedef typename Action::template result<env_type>::type type; |
| }; |
| |
| [endsect] |
| [section Actor Example] |
| |
| Let us see a very simple prototypical example of an actor. This is not a toy |
| example. This is actually part of the library. Remember the [link |
| phoenix.primitives.references `reference`]?. |
| |
| First, we have a model of the `Eval` concept: the `reference`: |
| |
| template <typename T> |
| struct reference |
| { |
| template <typename Env> |
| struct result |
| { |
| typedef T& type; |
| }; |
| |
| reference(T& arg) |
| : ref(arg) {} |
| |
| template <typename Env> |
| T& eval(Env const&) const |
| { |
| return ref; |
| } |
| |
| T& ref; |
| }; |
| |
| Models of `Eval` are never created directly and its instances never exist alone. |
| We have to wrap it inside the `actor` template class to be useful. The `ref` |
| template function does this for us: |
| |
| template <typename T> |
| actor<reference<T> > const |
| ref(T& v) |
| { |
| return reference<T>(v); |
| } |
| |
| The `reference` template class conforms to the __eval__ concept. It has a nested |
| `result` metafunction that reflects the return type of its `eval` member |
| function, which performs the actual function. `reference<T>` stores a reference to |
| a `T`. Its `eval` member function simply returns the reference. It does not make |
| use of the environment `Env`. |
| |
| /Pretty simple.../ |
| |
| [endsect] |
| [section Composites In Detail] |
| |
| We stated before that composites are actors that are composed of zero or more |
| actors (see [link phoenix.composite Composite]). This is not quite accurate. The |
| definition was sufficient at that point where we opted to keep things simple and |
| not bury the reader with details which she might not need anyway. |
| |
| Actually, a composite is a model of the __eval__ concept (more on this later). |
| At the same time, it is also composed of 0..N (where N is a predefined maximum) |
| __eval__ instances and an eval policy. The individual __eval__ instances are |
| stored in a tuple. |
| |
| [note In a sense, the original definition of "composite", more or |
| less, will do just fine because __eval__ instances never exist alone and are |
| always wrapped in an `actor` template class which inherits from it anyway. The |
| resulting actor IS-AN __eval__.] |
| |
| [note You can set `PHOENIX_COMPOSITE_LIMIT`, the predefined maximum |
| `Eval`s (actors) a composite can take. By default, `PHOENIX_COMPOSITE_LIMIT` is |
| set to `PHOENIX_LIMIT` (See [link phoenix.actors Actors]).] |
| |
| [h2 composite template class] |
| |
| template <typename EvalPolicy, typename EvalTuple> |
| struct composite : EvalTuple |
| { |
| typedef EvalTuple base_type; |
| typedef EvalPolicy eval_policy_type; |
| |
| template <typename Env> |
| struct result |
| { |
| typedef implementation-defined type; |
| }; |
| |
| composite(); |
| composite(base_type const& actors); |
| |
| template <typename U0> |
| composite(U0 const& _0); |
| |
| template <typename U0, typename U1> |
| composite(U0 const& _0, U1 const& _1); |
| |
| // more constructors |
| |
| template <typename Env> |
| typename result<Env>::type |
| eval(Env const& env) const; |
| }; |
| |
| [h2 EvalTuple] |
| |
| `EvalTuple`, holds all the __eval__ instances. The `composite` template class |
| inherits from it. In addition to a default constructor and a constructor from an |
| `EvalTuple` object, there are templated (pass through) constructors for 1 to N |
| arguments (again, where N == `PHOENIX_COMPOSITE_LIMIT`). These constructors |
| simply forward the arguments to the `EvalTuple` base class. |
| |
| [h2 EvalPolicy] |
| |
| The composite's `eval` member function calls its `EvalPolicy`'s `eval` member |
| function (a static member function) passing in the [link |
| phoenix.inside_phoenix.actors_in_detail.environment environment] and each of |
| its actors, in parallel. The following diagram illustrates what's happening: |
| |
| [$images/funnel_out.png] |
| |
| [table EvalPolicy Requirements |
| [ [Expression] [Result/Semantics] ] |
| [ [`x.eval<RT>(env, eval0, eval1, ..., evalN)`] [Evaluate the composite] ] |
| [ [`T::result<Env, Eval0, Eval1, Eval2, ..., EvalN>::type`] [The return type of eval] ] |
| ] |
| |
| The `EvalPolicy` is expected to have a nested template class `result` which has a |
| typedef `type` that reflects the return type of its member function `eval`. |
| Here's a typical example of the composite's eval member function for a 2-actor |
| composite: |
| |
| template <typename Env> |
| typename result<Env>::type |
| eval(Env const& env) const |
| { |
| typedef typename result<Env>::type return_type; |
| return EvalPolicy::template |
| eval<return_type>( |
| env |
| , get<0>(*this) // gets the 0th element from EvalTuple |
| , get<1>(*this)); // gets the 1st element from EvalTuple |
| } |
| |
| [endsect] |
| [section Composing] |
| |
| Composites are never instantiated directly. Front end expression templates are |
| used to generate the composites. Using expression templates, we implement a DSEL |
| (Domain Specific Embedded Language) that mimics native C++. You've seen this |
| DSEL in action in the preceding sections. It is most evident in the |
| [link phoenix.composite.statement Statement] section. |
| |
| There are some facilities in the library to make composition of composites |
| easier. We have a set of overloaded `compose` functions and an `as_composite` |
| metafunction. Together, these helpers make composing a breeze. We'll provide an |
| [link phoenix.inside_phoenix.composing.composite_example example of a |
| composite] later to see why. |
| |
| [section compose] |
| |
| compose<EvalPolicy>(arg0, arg1, arg2, ..., argN); |
| |
| Given an __eval_policy__ and some arguments `arg0`...argN, returns a proper |
| `composite`. The arguments may or may not be phoenix actors (primitives of |
| composites). If not, the arguments are converted to actors appropriately. For |
| example: |
| |
| compose<X>(3) |
| |
| converts the argument `3` to an `actor<value<int> >(3)`. |
| |
| [endsect] |
| |
| [section as_composite] |
| |
| as_composite<EvalPolicy, Arg0, Arg1, Arg2, ..., ArgN>::type |
| |
| This is the metafunction counterpart of `compose`. Given an __eval_policy__ and |
| some argument types `Arg0`...ArgN, returns a proper `composite` type. For |
| example: |
| |
| as_composite<X, int>::type |
| |
| is the composite type of the `compose<X>(3)` expression above. |
| |
| [endsect] |
| |
| [section Composite Example] |
| |
| Now, let's examine an example. Again, this is not a toy example. This is actually |
| part of the library. Remember the [link phoenix.composite.statement.while__statement |
| `while_`] lazy statement? Putting together everything we've learned so far, we |
| will present it here in its entirety (verbatim): |
| |
| struct while_eval |
| { |
| template <typename Env, typename Cond, typename Do> |
| struct result |
| { |
| typedef void type; |
| }; |
| |
| template <typename RT, typename Env, typename Cond, typename Do> |
| static void |
| eval(Env const& env, Cond& cond, Do& do_) |
| { |
| while (cond.eval(env)) |
| do_.eval(env); |
| } |
| }; |
| |
| template <typename Cond> |
| struct while_gen |
| { |
| while_gen(Cond const& cond) |
| : cond(cond) {} |
| |
| template <typename Do> |
| actor<typename as_composite<while_eval, Cond, Do>::type> |
| operator[](Do const& do_) const |
| { |
| return compose<while_eval>(cond, do_); |
| } |
| |
| Cond cond; |
| }; |
| |
| template <typename Cond> |
| while_gen<Cond> |
| while_(Cond const& cond) |
| { |
| return while_gen<Cond>(cond); |
| } |
| |
| `while_eval` is an example of an __eval_policy__. `while_gen` and `while_` are |
| the expression template front ends. Let's break this apart to understand what's |
| happening. Let's start at the bottom. It's easier that way. |
| |
| When you write: |
| |
| while_(cond) |
| |
| we generate an instance of `while_gen<Cond>`, where `Cond` is the type of |
| `cond`. `cond` can be an arbitrarily complex actor expression. The `while_gen` |
| template class has an `operator[]` accepting another expression. If we write: |
| |
| while_(cond) |
| [ |
| do_ |
| ] |
| |
| it will generate a proper composite with the type: |
| |
| as_composite<while_eval, Cond, Do>::type |
| |
| where `Cond` is the type of `cond` and `Do` is the type of `do_`. Notice how we |
| are using phoenix's [link phoenix.inside_phoenix.composing composition] (`compose` |
| and `as_composite`) mechanisms here |
| |
| template <typename Do> |
| actor<typename as_composite<while_eval, Cond, Do>::type> |
| operator[](Do const& do_) const |
| { |
| return compose<while_eval>(cond, do_); |
| } |
| |
| Finally, the `while_eval` does its thing: |
| |
| while (cond.eval(env)) |
| do_.eval(env); |
| |
| `cond` and `do_`, at this point, are instances of __eval__. `cond` and `do_` are |
| the __eval__ elements held by the composite's __eval_tuple__. `env` is the |
| __environment__. |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section Extending] |
| |
| We've shown how it is very easy to extend phoenix by writing new primitives and |
| composites. The modular design of Phoenix makes it extremely extensible. We have |
| seen that layer upon layer, the whole library is built on a solid foundation. |
| There are only a few simple well designed concepts that are laid out like |
| bricks. Overall, the library is designed to be extended. Everything above the |
| core layer can in fact be considered just as extensions to the library. This |
| modular design was inherited from the __spirit__ inline parser library. |
| |
| Extension is non-intrusive. And, whenever a component or module is extended, the |
| new extension automatically becomes a first class citizen and is automatically |
| recognized by all modules and components in the library. |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section Wrap Up] |
| |
| Sooner or later more FP techniques become standard practice as people find the |
| true value of this programming discipline outside the academy and into the |
| mainstream. In as much as structured programming of the 70s and object oriented |
| programming in the 80s and generic programming in the 90s shaped our thoughts |
| towards a more robust sense of software engineering, FP will certainly be a |
| paradigm that will catapult us towards more powerful software design and |
| engineering onward into the new millennium. |
| |
| Let me quote Doug Gregor of Boost.org. About functional style programming |
| libraries: |
| |
| [:['They're gaining acceptance, but are somewhat stunted by the ubiquitousness |
| of broken compilers. The C++ community is moving deeper into the so-called "STL- |
| style" programming paradigm, which brings many aspects of functional programming |
| into the fold. Look at, for instance, the Spirit parser to see how such function |
| objects can be used to build Yacc-like grammars with semantic actions that can |
| build abstract syntax trees on the fly. This type of functional composition is |
| gaining momentum.]] |
| |
| Indeed. Phoenix is another attempt to introduce more FP techniques into the |
| mainstream. Not only is it a tool that will make life easier for the programmer. |
| In its own right, the actual design of the library itself is a model of true C++ |
| FP in action. The library is designed and structured in a strict but clear and |
| well mannered FP sense. By all means, use the library as a tool. But for those |
| who want to learn more about FP in C++, don't stop there, I invite you to take a |
| closer look at the design of the library itself. |
| |
| So there you have it. Have fun! See you in the FP world. |
| |
| [endsect] |
| |
| [section Acknowledgement] |
| |
| # Hartmut Kaiser implemented the original lazy casts and constructors based on |
| his original work on Spirit SE "semantic expressions" (the precursor to |
| Phoenix). |
| # Angus Leeming implemented the container functions on Phoenix-1 which I then |
| ported to Phoenix-2. |
| # Daniel Wallin helped with the scope module, local variables, let and lambda |
| and the algorithms. I frequently discuss design issues with Daniel on Yahoo Messenger. |
| # Jaakko Jarvi. DA Lambda MAN! |
| # Dave Abrahams, for his constant presence, wherever, whenever. |
| # Aleksey Gurtovoy, DA MPL MAN! |
| # Doug Gregor, always a source of inspiration. |
| # Dan Marsden, did almost all the work in bringing Phoenix-2 out the door. |
| # Eric Niebler did a 2.0 pre-release review and wrote some range related code |
| that Phoenix stole and used in the algorithms. |
| # Thorsten Ottosen; Eric's range_ex code began life as "container_algo" in the |
| old boost sandbox, by Thorsten in 2002-2003. |
| # Jeremy Siek, even prior to Thorsten, in 2001, started the "container_algo". |
| # Vladimir Prus wrote the mutating algorithms code from the Boost Wiki. |
| # Daryle Walker did a 2.0 pre-release review. |
| |
| [endsect] |
| |
| [section References] |
| |
| # Why Functional Programming Matters, John Hughes, 1989. |
| Available online at [@http://www.math.chalmers.se/~rjmh/Papers/whyfp.html]. |
| # Boost.Lambda library, Jaakko Jarvi, 1999-2004 Jaakko Jarvi, Gary Powell. |
| Available online at [@http://www.boost.org/libs/lambda/]. |
| # Functional Programming in C++ using the FC++ Library: a short article |
| introducing FC++, Brian McNamara and Yannis Smaragdakis, August 2003. Available |
| online at [@http://www.cc.gatech.edu/~yannis/fc++/]. |
| # Side-effects and partial function application in C++, Jaakko Jarvi and Gary |
| Powell, 2001. Available online at |
| [@http://osl.iu.edu/~jajarvi/publications/papers/mpool01.pdf]. |
| # Spirit Version 1.8.1, Joel de Guzman, Nov 2004. Available online at |
| [@http://www.boost.org/libs/spirit/]. |
| # The Boost MPL Library, Aleksey Gurtovoy and David Abrahams, 2002-2004. |
| Available online at [@http://www.boost.org/libs/mpl/]. |
| # Generic Programming Redesign of Patterns, Proceedings of the 5th European |
| Conference on Pattern Languages of Programs, (EuroPLoP'2000) Irsee, Germany, |
| July 2000. Available online at |
| [@http://www.coldewey.com/europlop2000/papers/geraud%2Bduret.zip]. |
| # A Gentle Introduction to Haskell, Paul Hudak, John Peterson and Joseph Fasel, |
| 1999. Available online at [@http://www.haskell.org/tutorial/]. |
| # Large scale software design, John Lackos, ISBN 0201633620, Addison-Wesley, July |
| 1996. |
| # Design Patterns, Elements of Reusable Object-Oriented Software, Erich Gamma, |
| Richard Helm, Ralph Jhonson, and John Vlissides, Addison-Wesley, 1995. |
| # The Forwarding Problem: Arguments Peter Dimov, Howard E. Hinnant, Dave |
| Abrahams, September 09, 2002. Available online: __forwarding__. |
| |
| [endsect] |
| |