| Home | Libraries | People | FAQ | More

##### Transforms With State Accumulation

So far, we've only seen examples of grammars with transforms that accept one argument: the expression to transform. But consider for a moment how, in ordinary procedural code, you would turn a binary tree into a linked list. You would start with an empty list. Then, you would recursively convert the right branch to a list, and use the result as the initial state while converting the left branch to a list. That is, you would need a function that takes two parameters: the current node and the list so far. These sorts of accumulation problems are quite common when processing trees. The linked list is an example of an accumulation variable or state. Each iteration of the algorithm takes the current element and state, applies some binary function to the two and creates a new state. In the STL, this algorithm is called `std::accumulate()`. In many other languages, it is called fold. Let's see how to implement a fold algorithm with Proto transforms.

All Proto grammars can optionally accept a state parameter in addition to the expression to transform. If you want to fold a tree to a list, you'll need to make use of the state parameter to pass around the list you've built so far. As for the list, the Boost.Fusion library provides a `fusion::cons<>` type from which you can build heterogeneous lists. The type `fusion::nil` represents an empty list.

Below is a grammar that recognizes output expressions like `cout_ << 42 << '\n'` and puts the arguments into a Fusion list. It is explained below.

    // Fold the terminals in output statements like
    // "cout_ << 42 << '\n'" into a Fusion cons-list.
    struct FoldToList
      : proto::or_<
            // Don't add the ostream terminal to the list
            proto::when<
                proto::terminal< std::ostream & >
              , proto::_state
            >
            // Put all other terminals at the head of the
            // list that we're building in the "state" parameter
          , proto::when<
                proto::terminal<_>
              , fusion::cons<proto::_value, proto::_state>(
                    proto::_value, proto::_state
                )
            >
            // For left-shift operations, first fold the right
            // child to a list using the current state. Use
            // the result as the state parameter when folding
            // the left child to a list.
          , proto::when<
                proto::shift_left<FoldToList, FoldToList>
              , FoldToList(
                    proto::_left
                  , FoldToList(proto::_right, proto::_state)
                )
            >
        >
    {};

Before reading on, see if you can apply what you know already about object, callable and primitive transforms to figure out how this grammar works.

When you use the `FoldToList` function, you'll need to pass two arguments: the expression to fold, and the initial state: an empty list. Those two arguments get passed around to each transform. We learned previously that `proto::_value` is a primitive transform that accepts a terminal expression and extracts its value. What we didn't know until now was that it also accepts the current state and ignores it. `proto::_state` is also a primitive transform. It accepts the current expression, which it ignores, and the current state, which it returns.

When we find a terminal, we stick it at the head of the cons list, using the current state as the tail of the list. (The first alternate causes the `ostream` to be skipped. We don't want `cout` in the list.) When we find a shift-left node, we apply the following transform:

    // Fold the right child and use the result as
    // state while folding the right.
    FoldToList(
        proto::_left
      , FoldToList(proto::_right, proto::_state)
    )

You can read this transform as follows: using the current state, fold the right child to a list. Use the new list as the state while folding the left child to a list.

| Tip

If your compiler is Microsoft Visual C++, you'll find that the above transform does not compile. The compiler has bugs with its handling of nested function types. You can work around the bug by wrapping the inner transform in `proto::call<>` as follows:

    FoldToList(
        proto::_left
      , proto::call<FoldToList(proto::_right, proto::_state)>
    )

`proto::call<>` turns a callable transform into a primitive transform, but more on that later.

Now that we have defined the `FoldToList` function object, we can use it to turn output expressions into lists as follows:

    proto::terminal<std::ostream &>::type const cout_ = {std::cout};

    // This is the type of the list we build below
    typedef
        fusion::cons<
            int
          , fusion::cons<
                double
              , fusion::cons<
                    char
                  , fusion::nil
                >
            >
        >
    result_type;

    // Fold an output expression into a Fusion list, using
    // fusion::nil as the initial state of the transformation.
    FoldToList to_list;
    result_type args = to_list(cout_ << 1 << 3.14 << '\n', fusion::nil());

    // Now "args" is the list: {1, 3.14, '\n'}

When writing transforms, "fold" is such a basic operation that Proto provides a number of built-in fold transforms. We'll get to them later. For now, rest assured that you won't always have to stretch your brain so far to do such basic things.