On Mon, Oct 4, 2010 at 12:43 PM, Thomas Heller <thom.heller@googlemail.com> wrote:
On Mon, Oct 4, 2010 at 8:45 PM, Eric Niebler <eric@boostpro.com> wrote:
> On 10/4/2010 6:49 AM, Thomas Heller wrote:
>> Hi,
>>
>> I spent some time on thinking how one could make the traversal of a proto
>> expression tree easier. I know want to share my findings with you all, and
>> propose a new addition to proto.
>>
>> My first idea was to decouple grammars from transforms, to follow the idea of
>> separation of data and algorithm.
>
> Data and algorithm are already separate in Proto. "Data" is the
> expression to traverse. "Algorithm" is the transform, driven by
> pattern-matching in the grammar.

True, but you can only attach one grammar to one transform. Thus for
every transformation you want to make, you need (in theory) replicate
your grammar, see further down that this is not the case in real life.


OK, but let's be clear: Proto strictly enforces the separation of data and algorithm. The grammar is not part of the data. We have:

Expression: data
Grammar: schema
Transforms: algorithm

The idea of being able to specify the transforms separately from the grammar is conceptually very appealing. The grammar is the control flow, the transform the action. Passing in the transforms to a grammar would be like passing a function object to a standard algorithm: a very reasonable thing to do. I don't think we've yet found the right formulation for it, though. Visitors and tag dispatching are too ugly/hard to use.

I have some ideas. Let me think some.

 

>> Currently, a transform is only applyable
>> when a certain expression is matched, this is good and wanted, though
>> sometimes you get yourself into a situation that requires you to reformulate
>> your grammar, and just exchange the transform part.
>
> True. But in my experience, the grammar part is rarely unchanged.

Yep, unchanged, and therefore you don't want to write it again.


I said "rarely unchanged". That is, you would *have* to write it again in most cases.

 

>> Let me give you an example of a comma separated list of proto expression you
>> want to treat like an associative sequence:
>>
>>     opt1 = 1, opt2 = 2, opt3 = 3
>>
>> A proto grammar matching this expression would look something like this:
>>
>
> <snip>
>
>>
>> This code works and everybody is happy, right?
>> Ok, what will happen if we want to calculate the number of options we
>> provided in our expression?
>> The answer is that we most likely need to repeat almost everything from
>> pack. except the transform part:
>>
>>    struct size :
>>        or_<
>>            when<
>>                 comma<pack, spec>
>>               , mpl::plus<size(_left), size(_right)>()
>>            >
>>          , when<
>>                spec
>>              , mpl::int_<1>()
>>            >
>>        >
>>     {};
>
> This trivial example doesn't make your point, because the "grammar" that
> gets repeated ("comma<pack, spec>" and "spec") is such a tiny fraction
> of the algorithm.

Right, this example does not show the full potential.

>> Now think of it if you are having a very complicated grammar, c&p the whole
>> grammar, or even just parts of it no fun.
>
> This is true, but it can be alleviated in most (all?) cases by building
> grammars in stages, giving names to parts for reusability. For instance,
> if "comma<pack, spec>" were actually some very complicated grammar, you
> would do this:
>
>   struct packpart:
>     : comma<pack, spec>
>   {};
>
> And then reuse packpart in both algorithms.

Right, that also works!

<snip>

>
> I'm not opposed to such a thing being in Proto, but I (personally) don't
> feel a strong need. I'd be more willing if I saw a more strongly
> motivating example. I believe Joel Falcou invented something similar.
> Joel, what was your use scenario?
>
> I've also never been wild for proto::switch_, which I think is very
> syntax-heavy. It's needed as an alternative to proto::or_ to bring down
> the instantiation count, but it would be nice if visitor has a usage
> mode that didn't require creating a bunch of (partial) template
> specializations.

Ok, point taken. The partial specializations is also something i don't
like. I thought about
doing the same as you did with contexts (tag as parameter to operator() calls),
but decided against it, cause you would end up with an enormous set of
operator()
overloads. With this solution you end up with an enormous set of
classes, but this
solution is extendable (even from the outside), both from the grammar
part and the transform part. Meaning you can add new tags without
changing th intrinsics of your other grammars/transforms.


Yes, that's very important.

 

>
> I'll also point out that this solution is FAR more verbose that the
> original which duplicated part of the grammar. I also played with such
> visitors, but every solution I came up with suffered from this same
> verbosity problem.

Ok, the verbosity is a problem, agreed. I invented this because of
phoenix, actually. As a use case i wrote a small prototype with a
constant folder:
http://github.com/sithhell/boosties/blob/master/proto/libs/proto/test/phoenix_test.cpp


Neat! You're getting very good at Proto. :-)

 
Note that the phoenix grammar could end up growing very complex! But
users should still be able to add their own tags for their own
expressions. I decided to propose the visitor because Joel Falcou
showed interest in it (Because he invented something similiar for NT2,
remember one of the first prototypes for phoenix3? They were actually
based on the same concepts).

We abandoned those early prototypes. Now I can't remember why. Can you?