
proto::or_ (and I presume, but not verified, proto::and_) requires at least 2 arguments. It might be nice to allow 1 argument (and maybe 0 arguments as well). Zero and one can happen while playing around during development, but more importantly as the result of invoking other metafunctions computing grammars. Whether it is really an issue in practice, I cannot tell. For now I've hit this in the 'playing around' part, haven't needed to compute grammars yet. At least with GCC, the error you presently get when you try proto::or_ with one argument is that it requires 8 arguments, with no indication that anything between 2 and 8 would work. Arguably GCC error messages could be improved to take into consideration default aruments, but this is what 4.1.2 does. Best regards, Maurizio

Maurizio Vitale wrote:
proto::or_ (and I presume, but not verified, proto::and_) requires at least 2 arguments. It might be nice to allow 1 argument
I don't have strong feelings about this one. I see that in MPL, mpl::or_ requires at least 2 arguments. <shrug> Thx for the suggestion, I'll consider it. (and maybe 0 arguments as
well).
Ick, no. It's not obvious what it should mean. -- Eric Niebler Boost Consulting www.boost-consulting.com

(and maybe 0 arguments as
well).
Ick, no. It's not obvious what it should mean.
A way to define it would be similar to what scheme/lisp do for operators applied to no arguments: they return the identity for the operation. For logical and and or, the identities would be #t and #f. For grammars, and_ would be something that always matches and or_ would be something that never matches, Maybe not particularly useful here, because probably nobody recurses on grammars this way, but very useful to have in scheme and lisp. But I think having the same behaviour as mpl::and_ and mpl::or_ is very important, so if one is changed the other probably should as well. The nice thing about this change is that it shouldn't make any code that was valid invalid (unless there's a way to have SFINAE effects visible).

On 04/17/2007 09:24 PM, Maurizio Vitale wrote:
(and maybe 0 arguments as
well).
Ick, no. It's not obvious what it should mean.
A way to define it would be similar to what scheme/lisp do for operators applied to no arguments: they return the identity for the operation. For logical and and or, the identities would be #t and #f.
For grammars, and_ would be something that always matches and or_ would be something that never matches,
Maybe not particularly useful here, because probably nobody recurses on grammars this way, but very useful to have in scheme and lisp.
But I think having the same behaviour as mpl::and_ and mpl::or_ is very important, so if one is changed the other probably should as well. The nice thing about this change is that it shouldn't make any code that was valid invalid (unless there's a way to have SFINAE effects visible).
I've just encounted a need for something like this. For example, if you have a list of types for which you want to apply the or_ to, however, that list must by calculated, then the only way to apply or to it is with a fold operation. Since mpl::fold takes an argument represening the initial state, this would naturally be proto::or_<> in case you want to proto::or_ together a list of types. In my particular use case, I've got 3 enumerations: enum sym_inp{...}; enum sym_out{...}; enum sym_act{...} which correspond to the terminals, non-terminals, and action symbols in a grammar. Naturally, these would be used to define the proto::terminals in some proto representation of the grammar and I'd use mpl::fold and proto::or_ something like: struct grm_symbol : proto::or_ < inp<inp_0>::type , inp<inp_1>::type , out<out_0>::type , out<out_1>::type , out<out_2>::type
{}; where inp is just something derived from say: proto::terminal<some_wrap<inp_0> > Anyhow, I hope you get the idea. I'm still working on it, but this is what prompted me tho agree with Maurizio's suggestion that it'd be good to allow or_<>.

Larry Evans wrote:
On 04/17/2007 09:24 PM, Maurizio Vitale wrote:
(and maybe 0 arguments as
well).
<snip>
I've just encounted a need for something like this. For example, if you have a list of types for which you want to apply the or_ to, however, that list must by calculated, then the only way to apply or to it is with a fold operation. Since mpl::fold takes an argument represening the initial state, this would naturally be proto::or_<> in case you want to proto::or_ together a list of types. <snip>
Interesting. In order for this to work, proto::or_ would need to be an extensible mpl sequence, right? It currently is not. -- Eric Niebler Boost Consulting www.boost-consulting.com

On 04/18/2007 01:06 PM, Eric Niebler wrote:
Larry Evans wrote: [snip]
I've just encounted a need for something like this. For example, if you have a list of types for which you want to apply the or_ to, however, that list must by calculated, then the only way to apply or to it is with a fold operation. Since mpl::fold takes an argument represening the initial state, this would naturally be proto::or_<> in case you want to proto::or_ together a list of types.
<snip>
Interesting. In order for this to work, proto::or_ would need to be an extensible mpl sequence, right? [snip]
No. The input to fold has to be; however, the output produced doesn't. Here's what I've got so far: struct or_base ; template < class Head , class Tail
struct or_op { typedef proto::or_ < Head , typename Tail::type > type ; }; template < class Head
struct or_op < Head , or_base
{ typedef Head type ; }; typedef mpl::vector < inp<inp_0>::type , inp<inp_1>::type , out<out_0>::type , out<out_1>::type , out<out_2>::type
grm_syms ; struct grm_symbol : mpl::fold < grm_syms , or_base , or_op < mpl::arg<2> , mpl::arg<1> >
::type { };
And it appears to work.

On 04/19/2007 03:54 AM, Larry Evans wrote:
On 04/18/2007 01:06 PM, Eric Niebler wrote:
Larry Evans wrote:
[snip]
I've just encounted a need for something like this. For example, if you have a list of types for which you want to apply the or_ to, however, that list must by calculated, then the only way to apply or to it is with a fold operation. Since mpl::fold takes an argument represening the initial state, this would naturally be proto::or_<> in case you want to proto::or_ together a list of types.
<snip>
Interesting. In order for this to work, proto::or_ would need to be an extensible mpl sequence, right?
[snip]
No. The input to fold has to be; however, the output produced doesn't. [snip] I think the output could be adapted to conform to mpl sequence requirements. I've got a fold_seq template which does this, in case you're interested.

Larry Evans wrote:
On 04/18/2007 01:06 PM, Eric Niebler wrote:
Larry Evans wrote: [snip]
I've just encounted a need for something like this. For example, if you have a list of types for which you want to apply the or_ to, however, that list must by calculated, then the only way to apply or to it is with a fold operation. Since mpl::fold takes an argument represening the initial state, this would naturally be proto::or_<> in case you want to proto::or_ together a list of types. <snip>
Interesting. In order for this to work, proto::or_ would need to be an extensible mpl sequence, right? [snip]
No. The input to fold has to be; however, the output produced doesn't. Here's what I've got so far:
struct or_base ; template < class Head , class Tail
struct or_op { typedef proto::or_ < Head , typename Tail::type > type ;
Oh! You're chaining or_'s together. Sure, that works. So for your initial state, all you need is a pattern that never matches anything. For that, you can use proto::not<proto::_>. -- Eric Niebler Boost Consulting www.boost-consulting.com

On 04/19/2007 11:46 AM, Eric Niebler wrote: [snip]
Oh! You're chaining or_'s together. Sure, that works. So for your initial state, all you need is a pattern that never matches anything. For that, you can use proto::not<proto::_>.
I couldn't get that to compile; however, proto::logical_not<proto::_> does. Thanks.

Larry Evans wrote:
On 04/19/2007 11:46 AM, Eric Niebler wrote: [snip]
Oh! You're chaining or_'s together. Sure, that works. So for your initial state, all you need is a pattern that never matches anything. For that, you can use proto::not<proto::_>.
I couldn't get that to compile; however, proto::logical_not<proto::_> does. Thanks.
proto::not_<> is a fairly recent addition. Be sure you're sync'ed up. logical_not<_> is certainly not what you want here. It will successfully match proto expressions such as !as_expr('a'). You want something that will never match anything. You could also use proto::if_<mpl::always<mpl::false_> >. -- Eric Niebler Boost Consulting www.boost-consulting.com

On 04/19/2007 12:35 PM, Eric Niebler wrote:
Larry Evans wrote:
On 04/19/2007 11:46 AM, Eric Niebler wrote: [snip]
Oh! You're chaining or_'s together. Sure, that works. So for your initial state, all you need is a pattern that never matches anything. For that, you can use proto::not<proto::_>.
I couldn't get that to compile; however, proto::logical_not<proto::_> does. Thanks.
proto::not_<> is a fairly recent addition. Be sure you're sync'ed up. logical_not<_> is certainly not what you want here. It will successfully match proto expressions such as !as_expr('a'). You want something that will never match anything. You could also use proto::if_<mpl::always<mpl::false_> >.
Yeah, I thought about it some more and the name, logical_not, suggests that if the argument, X, doesn't match, then logical_not<X>, would match, which, as you've noted, is certainly not what I want. However, I think proto::not_ also suffers the same name confusion. Like logical_not<X>, I'd think not_<X> would mean "if X fails then not_<X> succeeds". proto::if_<mpl::always<mpl::false_> > is much clearer although more verbose. Maybe proto::always_false or maybe proto::no would be less confusing and about as verbose.

Larry Evans wrote:
On 04/19/2007 12:35 PM, Eric Niebler wrote:
Larry Evans wrote:
On 04/19/2007 11:46 AM, Eric Niebler wrote: [snip]
Oh! You're chaining or_'s together. Sure, that works. So for your initial state, all you need is a pattern that never matches anything. For that, you can use proto::not<proto::_>. I couldn't get that to compile; however, proto::logical_not<proto::_> does. Thanks.
proto::not_<> is a fairly recent addition. Be sure you're sync'ed up. logical_not<_> is certainly not what you want here. It will successfully match proto expressions such as !as_expr('a'). You want something that will never match anything. You could also use proto::if_<mpl::always<mpl::false_> >.
Yeah, I thought about it some more and the name, logical_not, suggests that if the argument, X, doesn't match, then logical_not<X>, would match, which, as you've noted, is certainly not what I want.
No, you're mixing two things up. logical_not<> doesn't logically negate its argument. It matches the ! operator. The pattern "logical_not< terminal< char > >" would match the expression template generated by !as_expr('a'). not_<> is different. It *does* logically negate its argument. The pattern "not_< terminal< char > >" will match any expression *except* those that match the pattern terminal<char>. The pattern _ is a wildcard that matches anything. So not_<_> is a degenerate pattern that matches nothing.
However, I think proto::not_ also suffers the same name confusion. Like logical_not<X>, I'd think not_<X> would mean "if X fails then not_<X> succeeds".
That's precisely what it does. -- Eric Niebler Boost Consulting www.boost-consulting.com

On 04/19/2007 09:33 PM, Eric Niebler wrote: [snip]
The pattern _ is a wildcard that matches anything. So not_<_> is a degenerate pattern that matches nothing.
The "wildcard" is the concept I was missing :( Although I remember reading about it, my mind was still thinking that proto's _ was somehow like mpl's _, i.e. somehow like an argument placeholder. Thanks very much for the clarification and please excuse my not rereading the docs. -regards, Larry

On 04/17/2007 09:24 PM, Maurizio Vitale wrote:
(and maybe 0 arguments as
well).
Ick, no. It's not obvious what it should mean.
A way to define it would be similar to what scheme/lisp do for operators applied to no arguments: they return the identity for the operation. For logical and and or, the identities would be #t and #f.
For grammars, and_ would be something that always matches and or_ would be something that never matches,
Maybe not particularly useful here, because probably nobody recurses on grammars this way, but very useful to have in scheme and lisp.
But I think having the same behaviour as mpl::and_ and mpl::or_ is very important, so if one is changed the other probably should as well. The nice thing about this change is that it shouldn't make any code that was valid invalid (unless there's a way to have SFINAE effects visible).
So, to summarize, what you want is: proto::and_<> == proto::_ proto::or_<> == proto::not_<_> where == means, "matches the same expressions". IOW, _ and not_<_> would be the "ones" of the and_ and or_ operators since: proto::and_<proto::and_<X0,X1,...,Xn>, proto::_ > == proto::and_<X0,X1,...,Xn> and likewise for or_ and proto::not_<_>. The zeros would be just the reverse. IOW, zero one ____ ___ and_: not_<_> _ or_ : _ not_<_>

On Apr 21, 2007, at 8:57 AM, Larry Evans wrote:
So, to summarize, what you want is:
proto::and_<> == proto::_ proto::or_<> == proto::not_<_>
where == means, "matches the same expressions". IOW, _ and not_<_> would be the "ones" of the and_ and or_ operators since:
proto::and_<proto::and_<X0,X1,...,Xn>, proto::_ > == proto::and_<X0,X1,...,Xn>
and likewise for or_ and proto::not_<_>. The zeros would be just the reverse. IOW,
zero one ____ ___ and_: not_<_> _ or_ : _ not_<_>
This would seem (to me) to be the logical extension, but I leave to people who have design/used the mpl longer than me to decide whether it is a good idea. I'm not sure I understand zeros and ones: the value which is interesting is the identity. In the case of additions (and ORs) the identity is a 'zero'. In the case of multiplications (and ANDs) the identity is a 'one'. The 'other' value (zero for multiplications and one for additions) seems to only be of interest for simplifying expressions, rather than being logically important, but I might miss something here. Best regards, Maurizio

On 04/21/2007 12:21 PM, Maurizio Vitale wrote: [snip]
I'm not sure I understand zeros and ones: the value which is interesting is the identity. In the case of additions (and ORs) the identity is a 'zero'. In the case of multiplications (and ANDs) the identity is a 'one'. The 'other' value (zero for multiplications and one for additions) seems to only be of interest for simplifying expressions, rather than being logically important, but I might miss something here.
I believe you do understand, except that both special values (one and zero) can be used for simplification. Any expression with 0 is simplified to 0 and any expression with 1 is simplified to the subexpression without the 1. Simplification was one application. For example, there's the following code: // sequence rule folds all >>'s together into a list // and wraps the result in a composite<> wrapper struct ToySpiritSequence : as_composite< proto::tag::right_shift , proto::trans::reverse_fold_to_list< proto::right_shift<ToySpiritGrammar, ToySpiritGrammar> > > {}; in the proto/test/toysprit2.cpp file. I'm just guessing, but I'd think this folding could be accompanied by simplification based on the above rules.

On 04/21/2007 07:57 AM, Larry Evans wrote:
On 04/17/2007 09:24 PM, Maurizio Vitale wrote: [snip] and likewise for or_ and proto::not_<_>. The zeros would be just the reverse. IOW,
zero one ____ ___ and_: not_<_> _ or_ : _ not_<_>
Actually, I think and_ and or_ are the meet and join of a lattice: http://en.wikipedia.org/wiki/Lattice_%28order%29 where: proto::_ is the top element proto::not_<proto::_> is the bottom element However, I'm not sure about this since I don't know if the and_ and or_ operations are associative and commutative, which is one of the requirements for a lattic (I think).

On Sun, 22 Apr 2007 12:31:44 +0200, Larry Evans <cppljevans@cox-internet.com> wrote:
Actually, I think and_ and or_ are the meet and join of a lattice:
http://en.wikipedia.org/wiki/Lattice_%28order%29
where:
proto::_ is the top element proto::not_<proto::_> is the bottom element
However, I'm not sure about this since I don't know if the and_ and or_ operations are associative and commutative, which is one of the requirements for a lattic (I think).
Well, the last word is up to the author's library, however I'd be surprised if the following relations were not valid: associativity: or_< T1, or_<T2, T3> > == or_< T1, T2, T3 > == or_< or_<T1, T2,>, T3 > and_< T1, and_<T2, T3> > == and_< T1, T2, T3 > == and_< and_<T1, T2,>, T3 > commutativity: or_< T, U > == or_< U, T > and_< T, U > == and_< U, T > absorption: or_< T, and_<T, U> > == T and_< T, or_<T, U> > == T obviously where "==" means logical equivalence not C++ data type equality. Distibutivity shuold hold, too. Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Marco wrote:
On Sun, 22 Apr 2007 12:31:44 +0200, Larry Evans <cppljevans@cox-internet.com> wrote:
Actually, I think and_ and or_ are the meet and join of a lattice:
http://en.wikipedia.org/wiki/Lattice_%28order%29
where:
proto::_ is the top element proto::not_<proto::_> is the bottom element
However, I'm not sure about this since I don't know if the and_ and or_ operations are associative and commutative, which is one of the requirements for a lattic (I think).
Well, the last word is up to the author's library, however I'd be surprised if the following relations were not valid:
associativity: or_< T1, or_<T2, T3> > == or_< T1, T2, T3 > == or_< or_<T1, T2,>, T3 > and_< T1, and_<T2, T3> > == and_< T1, T2, T3 > == and_< and_<T1, T2,>, T3 >
Excuse my mathematical pedantry and going off topic. The operations or_ and and_ are binary, not ternary. Each of the middle expressions is, by definition (that is, mathematical consensus), equal to at least one of the corresponding outer terms. One or both of the equalities in each of the above relations is therefore tautologous (that is, always true). The only requirement for associativity is: or_< T1, or_<T2, T3> > == or_< or_<T1, T2,>, T3 > and_< T1, and_<T2, T3> > == and_< and_<T1, T2,>, T3 >

On Mon, 23 Apr 2007 11:11:04 +0200, Paul Giaccone <paulg@cinesite.co.uk> wrote:
Marco wrote:
Well, the last word is up to the author's library, however I'd be surprised if the following relations were not valid:
associativity: or_< T1, or_<T2, T3> > == or_< T1, T2, T3 > == or_< or_<T1, T2,>, T3 > and_< T1, and_<T2, T3> > == and_< T1, T2, T3 > == and_< and_<T1, T2,>, T3 >
Excuse my mathematical pedantry and going off topic. The operations or_ and and_ are binary, not ternary. Each of the middle expressions is, by definition (that is, mathematical consensus), equal to at least one of the corresponding outer terms. One or both of the equalities in each of the above relations is therefore tautologous (that is, always true).
The only requirement for associativity is:
or_< T1, or_<T2, T3> > == or_< or_<T1, T2,>, T3 > #1 and_< T1, and_<T2, T3> > == and_< and_<T1, T2,>, T3 > #2
I agree the only requirements for associativity are the equalities #1 and #2. The middle term in my relations has to be seen as the demonstration (IMO) that associativity really holds. Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Marco wrote:
Well, the last word is up to the author's library, however I'd be surprised if the following relations were not valid:
associativity: or_< T1, or_<T2, T3> > == or_< T1, T2, T3 > == or_< or_<T1, T2,>, T3 > and_< T1, and_<T2, T3> > == and_< T1, T2, T3 > == and_< and_<T1, T2,>, T3 >
commutativity: or_< T, U > == or_< U, T > and_< T, U > == and_< U, T >
absorption: or_< T, and_<T, U> > == T and_< T, or_<T, U> > == T
obviously where "==" means logical equivalence not C++ data type equality.
Yes, these relationships hold. My only considerations wrt the proposed extensions to proto::and_ and proto::or_ are: 1) Does it increase genericity? 2) Does it reduce bugs and/or increase discoverability in proto's interface? 3) Does it hurt compile times in the general case? Sounds like the answers to (1) and (2) are "Yes, somewhat." I'd need to measure to answer (3). -- Eric Niebler Boost Consulting www.boost-consulting.com
participants (6)
-
Eric Niebler
-
Larry Evans
-
Marco
-
Maurizio Vitale
-
Maurizio Vitale
-
Paul Giaccone