| Home | Libraries | People | FAQ | More

##### Implicit Parameters to Primitive Transforms

Let's use `FoldToList` example from the previous two sections to illustrate some other niceties of Proto transforms. We've seen that grammars, when used as function objects, can accept up to 3 parameters, and that when using these grammars in callable transforms, you can also specify up to 3 parameters. Let's take another look at the transform associated with non-terminals from the last section:

    FoldToList(
        proto::_left
      , FoldToList(proto::_right, proto::_state, proto::_data)
      , proto::_data
    )

Here we specify all three parameters to both invocations of the `FoldToList` grammar. But we don't have to specify all three. If we don't specify a third parameter, `proto::_data` is assumed. Likewise for the second parameter and `proto::_state`. So the above transform could have been written more simply as:

    FoldToList(
        proto::_left
      , StringCopy(proto::_right)
    )

The same is true for any primitive transform. The following are all equivalent:

Table 1.9. Implicit Parameters to Primitive Transforms

Equivalent Transforms
`proto::when<_, FoldToList>`
`proto::when<_, FoldToList()>`
`proto::when<_, FoldToList(_)>`
`proto::when<_, FoldToList(_, proto::_state)>`
`proto::when<_, FoldToList(_, proto::_state, proto::_data)>`

| Note
Grammars Are Primitive Transforms Are Function Objects So far, we've said that all Proto grammars are function objects. But it's more accurate to say that Proto grammars are primitive transforms -- a special kind of function object that takes between 1 and 3 arguments, and that Proto knows to treat specially when used in a callable transform, as in the table above.

| Note

Not All Function Objects Are Primitive Transforms

You might be tempted now to drop the `_state` and `_data` parameters for all your callable transforms. That would be an error. You can only do that for primitive transforms, and not all callables are primitive transforms. Later on, we'll see what distinguishes ordinary callables from their more powerful primitive transfor cousins, but the short version is this: primitive transforms inherit from `proto::transform<>`.

Once you know that primitive transforms will always receive all three parameters -- expression, state, and data -- it makes things possible that wouldn't be otherwise. For instance, consider that for binary expressions, these two transforms are equivalent. Can you see why?

Table 1.10. Two Equivalent Transforms

Without `proto::reverse_fold<>` | With `proto::reverse_fold<>`
--- | ---

    FoldToList(
        proto::_left
      , FoldToList(proto::_right, proto::_state, proto::_data)
      , proto::_data
    )

    proto::reverse_fold<_, proto::_state, FoldToList>