
This is not a review, sorry. Is it a goal of phoenix::bind to one day replace lambda::bind and boost::bind, being a superset of both, as well of std::bind? I have hoped for boost::lambda::bind to supercede boost::bind. It is a common claim that the only advantage of boost::bind is that it works on more compilers. But this isn't true. It supports constructs which lambda::bind does not; using smart pointers with member functions, member functions of abstract classes, proper const propagation, is_placeholder, _4.._9, and so on. There were other differences (lack of result_type support...) for which I was able to contribute patches to Lambda. But some of the differences are systemic and can only be addressed by a maintainer. Having two components named "bind" has always been a problem for our users. Having three will not help. Ideally, all "bind"s ought to resolve (on a supported compiler circa '08) to the same component. When I heard that the next Phoenix (at the time this meant V2) was intended to be the successor to both Phoenix 1 and Lambda, I thought that we were about to finally have a single bind that "just works". But - and sorry if this is not the case - I do not get the impression that this is a high priority goal for V2. It'd be nice if I were mistaken; it would be nicer still if phoenix::bind passed all boost::bind tests so that we can just replace boost/bind.hpp with a single using declaration. :-) To avoid any misunderstandings: this is not a review, and the above is not a condition for acceptance.

Peter Dimov wrote:
This is not a review, sorry.
Is it a goal of phoenix::bind to one day replace lambda::bind and boost::bind, being a superset of both, as well of std::bind?
lambda::bind, yes. std::bind cannot be replaced. boost::bind, too, IMO cannot be replaced, not in a long time, due to, as you said below, it works on more compilers.
I have hoped for boost::lambda::bind to supercede boost::bind. It is a common claim that the only advantage of boost::bind is that it works on more compilers. But this isn't true. It supports constructs which lambda::bind does not; using smart pointers with member functions, member functions of abstract classes, proper const propagation, is_placeholder, _4.._9, and so on. There were other differences (lack of result_type support...) for which I was able to contribute patches to Lambda. But some of the differences are systemic and can only be addressed by a maintainer.
I can definitely make sure that all those are supported. I supported the lambda tests in phoenix. I can do the same for boost::bind tests in phoenix.
Having two components named "bind" has always been a problem for our users. Having three will not help. Ideally, all "bind"s ought to resolve (on a supported compiler circa '08) to the same component.
Sure. Just like what John Maddock did with TR1 tuples targetting Fuson.Tuples. That can be done.
When I heard that the next Phoenix (at the time this meant V2) was intended to be the successor to both Phoenix 1 and Lambda, I thought that we were about to finally have a single bind that "just works".
Except on broken compilers though. That's the main reason why I think boost.bind will be with us for a long time still.
But - and sorry if this is not the case - I do not get the impression that this is a high priority goal for V2. It'd be nice if I were mistaken; it would be nicer still if phoenix::bind passed all boost::bind tests so that we can just replace boost/bind.hpp with a single using declaration. :-)
It is a priority for Phoenix. I'll make sure that all boost::bind tests will pass. Thanks for your comments. All points noted. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman:
Peter Dimov wrote: ...
Is it a goal of phoenix::bind to one day replace lambda::bind and boost::bind, being a superset of both, as well of std::bind?
lambda::bind, yes. std::bind cannot be replaced. boost::bind, too, IMO cannot be replaced, not in a long time, due to, as you said below, it works on more compilers.
It can be replaced on the compilers on which Phoenix works. It can also conform to the specification of std::bind, allowing people to move code back and forth.
I supported the lambda tests in phoenix.
This is very reassuring. Have you considered making a "reimplementation" of Lambda's headers part of the reviewed library? Might this be a feature that would convince people that it is not necessary to wait for V3 in order to "accept" Phoenix? Lambda's interface is stable and moving from V2 to V3 will not affect its users.

Peter Dimov wrote:
Joel de Guzman:
Peter Dimov wrote: ...
Is it a goal of phoenix::bind to one day replace lambda::bind and boost::bind, being a superset of both, as well of std::bind?
lambda::bind, yes. std::bind cannot be replaced. boost::bind, too, IMO cannot be replaced, not in a long time, due to, as you said below, it works on more compilers.
It can be replaced on the compilers on which Phoenix works. It can also conform to the specification of std::bind, allowing people to move code back and forth.
This should be possible, and I agree it would be a Good Thing.
I supported the lambda tests in phoenix.
This is very reassuring. Have you considered making a "reimplementation" of Lambda's headers part of the reviewed library? Might this be a feature that would convince people that it is not necessary to wait for V3 in order to "accept" Phoenix? Lambda's interface is stable and moving from V2 to V3 will not affect its users.
I have re-implemented both lambda and phoenix on top of proto, and IMO I don't believe phoenix should provide a 100% backwards-compatible lambda interface. Lambda has some quirks that it would be best to leave behind. Lambda and phoenix differ as to whether local variables are captured by value or by reference (phoenix always captures by value, lambda tries to guess what you intend based on usage). This is a fundamental difference -- difficult to reconcile. I support Joel's approach of deprecating the old lambda interface and migrating folks to phoenix. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler:
Lambda and phoenix differ as to whether local variables are captured by value or by reference (phoenix always captures by value, lambda tries to guess what you intend based on usage).
Are you sure that int v[] = { 1, 2, 3 }; std::for_each( v, v + 3, std::cout << arg1 << std::endl ); captures std::cout by value? :-)

Peter Dimov wrote:
Eric Niebler:
Lambda and phoenix differ as to whether local variables are captured by value or by reference (phoenix always captures by value, lambda tries to guess what you intend based on usage).
Are you sure that
int v[] = { 1, 2, 3 }; std::for_each( v, v + 3, std::cout << arg1 << std::endl );
captures std::cout by value? :-)
OK, OK, you got me. Even for Phoenix, the rules are not simple. Phoenix captures by value *when it can* (except for arrays, which are by reference, I think), or when the user specifies by-ref with phoenix::ref. But the decision is based on object's type, not on how the object is used in the expression, as it is with boost.lambda. Consider that with boost.lambda: int ii = 0; ii += _1; // ii captured by reference here ... _1 += ii; // ... but ii captured by value here -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler:
OK, OK, you got me. Even for Phoenix, the rules are not simple. Phoenix captures by value *when it can* (except for arrays, which are by reference, I think), or when the user specifies by-ref with phoenix::ref. But the decision is based on object's type, not on how the object is used in the expression, as it is with boost.lambda. Consider that with boost.lambda:
int ii = 0; ii += _1; // ii captured by reference here ... _1 += ii; // ... but ii captured by value here
Right. As with std::cout, this is being done for usability reasons. The demand for op= to capture its left operand by value is nonexistent. I do not necessarily claim that Lambda is right. After all, boost::bind deliberately captures by value in situations in which it knows that by-ref is more common. Normally, I'd state that both Lambda and Phoenix need to pick one over the other and stick with it. But there is a problem with this as well in that it could affect the eventual compatibility with boost::bind. boost::bind dutifully propagates its constness to the bound object and its arguments. In bind( f, a )(), f and a are non-const, because bind(f,a) isn't. Phoenix doesn't. It always "constifies" its contents. This is a good thing for ii += _1 because it allows it to fail. Const propagation is less of an issue in Phoenix because it has true local variables. With boost::bind and a suitably defined f, one can do boost::bind( f, 0, 0, _1 ) to approximate a lambda with two local variables, initially 0, and one argument. Phoenix doesn't need such tricks. But the question needs to be considered, and a balance has to be struck. (It's also possible to only constify the left side of op=, which is also a bit of a hack, but would be a net usability win.)

Peter Dimov wrote:
Eric Niebler:
OK, OK, you got me. Even for Phoenix, the rules are not simple. Phoenix captures by value *when it can* (except for arrays, which are by reference, I think), or when the user specifies by-ref with phoenix::ref. But the decision is based on object's type, not on how the object is used in the expression, as it is with boost.lambda. Consider that with boost.lambda:
int ii = 0; ii += _1; // ii captured by reference here ... _1 += ii; // ... but ii captured by value here
Right. As with std::cout, this is being done for usability reasons. The demand for op= to capture its left operand by value is nonexistent.
I do not necessarily claim that Lambda is right. After all, boost::bind deliberately captures by value in situations in which it knows that by-ref is more common.
Normally, I'd state that both Lambda and Phoenix need to pick one over the other and stick with it.
Alright, let's put it to a vote then. Here's my vote: Capture expressions by value: +1 Capture special objects by ref (e.g. cout, endl, arrays): +1 In addition, I'd like to provide a customization point for allowing certain objects to be captured by reference, cout, endl, arrays being provided out of the box. Something like: template <> struct capture_by_ref<MyClass> : mpl::true_ {};
But there is a problem with this as well in that it could affect the eventual compatibility with boost::bind.
boost::bind dutifully propagates its constness to the bound object and its arguments. In bind( f, a )(), f and a are non-const, because bind(f,a) isn't. Phoenix doesn't. It always "constifies" its contents. This is a good thing for
ii += _1
because it allows it to fail.
Const propagation is less of an issue in Phoenix because it has true local variables. With boost::bind and a suitably defined f, one can do
boost::bind( f, 0, 0, _1 )
to approximate a lambda with two local variables, initially 0, and one argument.
That's a nice trick! That can be quite useful on certain occasions.
Phoenix doesn't need such tricks. But the question needs to be considered, and a balance has to be struck.
What do you think would be a good balance? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman:
Alright, let's put it to a vote then. Here's my vote:
Capture expressions by value: +1 Capture special objects by ref (e.g. cout, endl, arrays): +1
This is not that different from Lambda, except that it has Capture left side of = and @= by ref: +0.5
Const propagation is less of an issue in Phoenix because it has true local variables. With boost::bind and a suitably defined f, one can do
boost::bind( f, 0, 0, _1 )
to approximate a lambda with two local variables, initially 0, and one argument.
That's a nice trick! That can be quite useful on certain occasions.
If you manage to include both Phoenix and boost::bind, you can do a generator function that returns 1, 2, 3... with: boost::bind<int>( ++arg1, 0 ) Of course if you have Phoenix you should be able to do the same with lambda( _a = 0 )[ ++_a ] but it doesn't seem to work. Maybe I'm doing something wrong. :-)
Phoenix doesn't need such tricks. But the question needs to be considered, and a balance has to be struck.
What do you think would be a good balance?
I'm not sure yet. I like the const propagation feature of boost::bind, but I can't say how it'd work in the larger Phoenix context, and whether it wouldn't prove too error-prone for casual use.

Peter Dimov wrote:
With boost::bind and a suitably defined f, one can do
boost::bind( f, 0, 0, _1 )
to approximate a lambda with two local variables, initially 0, and one argument.
That's a nice trick! That can be quite useful on certain occasions.
If you manage to include both Phoenix and boost::bind, you can do a generator function that returns 1, 2, 3... with:
boost::bind<int>( ++arg1, 0 )
Of course if you have Phoenix you should be able to do the same with
lambda( _a = 0 )[ ++_a ]
but it doesn't seem to work. Maybe I'm doing something wrong. :-)
Maybe you want: let(_a = 0)[ ++_a ] and herein I think lies the general misconception about Phoenix lambda (and possibly a flaw in the general API). The bottom line is that lambda introduces a new scope. It is somewhat a cousin of BLL protect in that the lambda[...]. It returns a lambda function that returns a lambda function. I once called it the lambda-lambda. It came about when trying to implement this: - \ \ double - /\ f . /\ x. f(f x) - / \ / \ in the original Phoenix1 implementation. Later, I realized it is the same motivation behind protect, albeit in a less general sense (from the lambda docs): "Primary motivation for including protect into the library, was to allow nested STL algorithm invocations (the section called “Nesting STL algorithm invocations” [http://tinyurl.com/5xm6rt])." Phoenix had lazy functions since its inception. The general problem was how to implement a higher-order-function that accepts higher- order-function. Like say: phx::for_each(_1, std::cout << _1 << std::endl) substituting the left _1 for the container. The right _1 substitutes the container's element which happens when for_each invokes the input function for each element: f(element). But that can't happen because all _1 will be substituted eagerly. hence, it was necessary to brace the higher-order-function argument: phx::for_each(_1, lambda[std::cout << _1 << std::endl]) Notice that like protect, there are two function invocations happening here. Each lambda introduces a new scope. Therefore for every lambda, there is one more additional function invocation. Examples: int x = 1; long x2 = 2; short x3 = 3; char const* y = "hello"; zzz z; BOOST_TEST(lambda[_1](x)(y) == y); BOOST_TEST(lambda(_a = _1)[_a](x)(y) == x); BOOST_TEST(lambda(_a = _1)[lambda[_a]](x)(y)(z) == x); BOOST_TEST(lambda(_a = _1)[lambda[_a + _1]](x)(y)(x) == 2); BOOST_TEST(lambda(_a = _1)[lambda(_b = _1)[_a + _b + _1]](x)(x2)(x3) == 6); This is all in line with the motivation: to have a phoenix function take in another phoenix (higher-order) function. Now, in contrast, the phoenix "let" does not introduce another scope. Examples: { int x = 1; BOOST_TEST( let(_a = _1) [ _a ] (x) == x ); } { int x = 1, y = 10; BOOST_TEST( let(_a = _1, _b = _2) [ _a + _b ] (x, y) == x + y ); } It seems to me now that it is the "let" behavior (no new scopes introduced) that folks like Giovanni needs for lambda (with or without the local variables). It is also in line with your recent P.S.: lambda()[ ... ] should work and be an alias for lambda[ ... ] (if we substitute lambda for let and allow in to have a null declaration). Ok, so pardon me if this is long and winding. I'm brain storming myself as I write this (short of talking out loud). I think: * The let behavior is what most people need. We can arrange it such that lambda assumes the let behavior, but only when placed in the outermost expression. * Now what about higher order function arguments? I think it is still possible to introduce a new scope (ONLY IF) the lambda is placed inside an actor. Let me see if I an come up with an update to V2 with these changes. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Wed, Oct 1, 2008 at 5:32 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
Peter Dimov wrote:
With boost::bind and a suitably defined f, one can do
boost::bind( f, 0, 0, _1 )
to approximate a lambda with two local variables, initially 0, and one argument.
That's a nice trick! That can be quite useful on certain occasions.
If you manage to include both Phoenix and boost::bind, you can do a generator function that returns 1, 2, 3... with:
boost::bind<int>( ++arg1, 0 )
Of course if you have Phoenix you should be able to do the same with
lambda( _a = 0 )[ ++_a ]
but it doesn't seem to work. Maybe I'm doing something wrong. :-)
Maybe you want:
let(_a = 0)[ ++_a ]
and herein I think lies the general misconception about Phoenix lambda (and possibly a flaw in the general API).
The bottom line is that lambda introduces a new scope. It is somewhat a cousin of BLL protect in that the lambda[...]. It returns a lambda function that returns a lambda function. I once called it the lambda-lambda. It came about when trying to implement this:
- \ \ double - /\ f . /\ x. f(f x) - / \ / \
It looks a bit messed up. Is that the same as this: (haskel syntax: '\' is lambda and function application doesn't require parenthesis) double = \f -> \ x -> f f x
in the original Phoenix1 implementation. Later, I realized it is the same motivation behind protect, albeit in a less general sense (from the lambda docs):
"Primary motivation for including protect into the library, was to allow nested STL algorithm invocations (the section called "Nesting STL algorithm invocations" [http://tinyurl.com/5xm6rt])."
I never got that detail. How is protect better in that case than using unlambda? Why would I want to mask a lambda just for one evaluation round and not forever?
Phoenix had lazy functions since its inception. The general problem was how to implement a higher-order-function that accepts higher- order-function. Like say:
phx::for_each(_1, std::cout << _1 << std::endl)
substituting the left _1 for the container. The right _1 substitutes the container's element which happens when for_each invokes the input function for each element: f(element).
But that can't happen because all _1 will be substituted eagerly. hence, it was necessary to brace the higher-order-function argument:
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Ok, I do exactly the same with a modified boost.lambda, except that the 'lambda[]' syntax has 'unlambda' semantics, not 'protect'
Notice that like protect, there are two function invocations happening here.
And this is where I get a bit lost. Why protect and lambda[] have to add another function evaluation round? I understand that in phoenix the extra round is to initialize the local variables, but I find it surprising: why has this to be exposed to the user? can't phoenix use an internal gateway to do it? I think as 'lambda' exactly as the lambda symbol in lambda calculus (\ in haskel). Think of the following expression in haskell (ignoring the fact that print has side effects): (\x -> for_each x (\y -> print y)) Now, translate every (\..) with lambda[] lambda[ for_each(_1, lambda[ print(_1) ]) ] IMHO the top level lambda is still introducing a new scope for the placeholder, so it is really not a special case. If you remove the top level lambda (which is not required by phoenix), the result is pretty much your initial phoenix expression. Now (\y -> print y) is an expression that returns an unary function, so I would expect lambda[ print(_1)] to also return a nullary. When nested inside a lambda expression, phoenix takes care itself of the extra evaluation round, but that is not the case when used top level. -- gpd

Giovanni Piero Deretta wrote:
On Wed, Oct 1, 2008 at 5:32 AM, Joel de Guzman
"Primary motivation for including protect into the library, was to allow nested STL algorithm invocations (the section called "Nesting STL algorithm invocations" [http://tinyurl.com/5xm6rt])."
I never got that detail. How is protect better in that case than using unlambda? Why would I want to mask a lambda just for one evaluation round and not forever?
Because you can't use unlambda there. See my other post.
Phoenix had lazy functions since its inception. The general problem was how to implement a higher-order-function that accepts higher- order-function. Like say:
phx::for_each(_1, std::cout << _1 << std::endl)
substituting the left _1 for the container. The right _1 substitutes the container's element which happens when for_each invokes the input function for each element: f(element).
But that can't happen because all _1 will be substituted eagerly. hence, it was necessary to brace the higher-order-function argument:
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Ok, I do exactly the same with a modified boost.lambda, except that the 'lambda[]' syntax has 'unlambda' semantics, not 'protect'
No it does not. Again, please see my other post. I'll delay my answer to the rest of this post after we sync our understanding. As of now, we are not in the same page. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Oct 2, 2008 at 4:53 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
On Wed, Oct 1, 2008 at 5:32 AM, Joel de Guzman
"Primary motivation for including protect into the library, was to allow nested STL algorithm invocations (the section called "Nesting STL algorithm invocations" [http://tinyurl.com/5xm6rt])."
I never got that detail. How is protect better in that case than using unlambda? Why would I want to mask a lambda just for one evaluation round and not forever?
Because you can't use unlambda there. See my other post.
Phoenix had lazy functions since its inception. The general problem was how to implement a higher-order-function that accepts higher- order-function. Like say:
phx::for_each(_1, std::cout << _1 << std::endl)
substituting the left _1 for the container. The right _1 substitutes the container's element which happens when for_each invokes the input function for each element: f(element).
But that can't happen because all _1 will be substituted eagerly. hence, it was necessary to brace the higher-order-function argument:
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Ok, I do exactly the same with a modified boost.lambda, except that the 'lambda[]' syntax has 'unlambda' semantics, not 'protect'
No it does not.
Oh yes, I'm sure it does, otherwise my code wouldn't work :) Long answer in the other post. -- gpd

Joel de Guzman:
Maybe you want:
let(_a = 0)[ ++_a ]
Maybe I do. :-)
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Notice that like protect, there are two function invocations happening here.
The confusion here comes from the fact that the above would work if lambda[] had "unlambda" semantics, that is, if it returned a function object that was not a phoenix expression.
- \ \ double - /\ f . /\ x. f(f x) - / \ / \
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ] ?

Peter Dimov wrote:
Joel de Guzman:
Maybe you want:
let(_a = 0)[ ++_a ]
Maybe I do. :-)
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Notice that like protect, there are two function invocations happening here.
The confusion here comes from the fact that the above would work if lambda[] had "unlambda" semantics, that is, if it returned a function object that was not a phoenix expression.
No, that is not the "unlambda" semantics. There needs to be 2 function application there: 1) the one that substitutes the stl container for _1 (the leftmost _1) and 2) the one that substitutes the container's element for _1 (the rightmost _1). The key point here is that phx.lambda (and BLL protect), *returns a lambda-functor that returns a lambda-functor*. unlambda OTOH simply returns a plain functor (non-actor). A plain functor can only do one function application (bear in mind that this is phoenix for_each (lazy), not std::for_each (eager)). Here's the crucial difference (using BLL) highlighting the difference: { int x = 5; int r = bind(_1, _2)(unlambda(_1), x); BOOST_TEST(x == 5); } { int x = 5; int r = bind(_1, _2)(protect(_1)(), x); BOOST_TEST(x == 5); } Notice that protect *requires* the additional function application: protect(_1)() I'm CC'ing Jaakko for clarification. It's also plausible that I am confused. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
{ int x = 5; int r = bind(_1, _2)(unlambda(_1), x); BOOST_TEST(x == 5);
----------^^^^^^^^^^^^^^^^^^ Oops: BOOST_TEST(r == 5); Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Oct 2, 2008 at 4:46 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
Peter Dimov wrote:
Joel de Guzman:
Maybe you want:
let(_a = 0)[ ++_a ]
Maybe I do. :-)
phx::for_each(_1, lambda[std::cout << _1 << std::endl])
Notice that like protect, there are two function invocations happening here.
The confusion here comes from the fact that the above would work if lambda[] had "unlambda" semantics, that is, if it returned a function object that was not a phoenix expression.
No, that is not the "unlambda" semantics. There needs to be 2 function application there: 1) the one that substitutes the stl container for _1 (the leftmost _1) and 2) the one that substitutes the container's element for _1 (the rightmost _1). The key point here is that phx.lambda (and BLL protect), *returns a lambda-functor that returns a lambda-functor*. unlambda OTOH simply returns a plain functor (non-actor). A plain functor can only do one function application (bear in mind that this is phoenix for_each (lazy), not std::for_each (eager)).
Ok, follow me: let 'f' me an unary function object, one suitable as a parameter to for_each: Am I right that the following calls should work and apply every element of some range to 'f'? phx::for_each(_1, f)(some_range); Ok, now 'f' is unlambda(std::cout << _1 << std::endl) (assuming phoenix had unlambda with the same semantics of boost::lambda::unlambda. Isn't the previous example still supposed to work? From phoenix point of view, the internal lambda expression is masked so it is treated as any other function object. The problem is of course that this prevent binding local lambda variables to placeholders of the outer lambda expression: phoenix will not recongnize the result of lambda[] as part of the lambda expression but will treat it as an opaque function object, so it there is no extra evaluation round for binding the actual arguments of the outer lambda expression to the local variables. Still I'm sure you can come out with a protocol to do that without requiring the extra round to be shown to the user.
Here's the crucial difference (using BLL) highlighting the difference:
{ int x = 5; int r = bind(_1, _2)(unlambda(_1), x); BOOST_TEST(x == 5); }
{ int x = 5; int r = bind(_1, _2)(protect(_1)(), x); BOOST_TEST(x == 5); }
Notice that protect *requires* the additional function application:
protect(_1)()
I understand the difference, but what buys us? What is the advantage? It feels a bit like an internal detail leaking... -- gpd

Giovanni Piero Deretta wrote:
No, that is not the "unlambda" semantics. There needs to be 2 function application there: 1) the one that substitutes the stl container for _1 (the leftmost _1) and 2) the one that substitutes the container's element for _1 (the rightmost _1). The key point here is that phx.lambda (and BLL protect), *returns a lambda-functor that returns a lambda-functor*. unlambda OTOH simply returns a plain functor (non-actor). A plain functor can only do one function application (bear in mind that this is phoenix for_each (lazy), not std::for_each (eager)).
Ok, follow me:
let 'f' me an unary function object, one suitable as a parameter to for_each: Am I right that the following calls should work and apply every element of some range to 'f'?
phx::for_each(_1, f)(some_range);
No. Not unless you bind f.
Ok, now 'f' is unlambda(std::cout << _1 << std::endl) (assuming phoenix had unlambda with the same semantics of boost::lambda::unlambda. Isn't the previous example still supposed to work? From phoenix point of view, the internal lambda expression is masked so it is treated as any other function object.
No it won't work, unless you bind it. An arbitrary function object is not lazy -- it is no different than an ordinary function. f must be a lambda function, not an ordinary function (or function object). And, in addition to that, it must be lambda function that returns a lambda function.
The problem is of course that this prevent binding local lambda variables to placeholders of the outer lambda expression: phoenix will not recongnize the result of lambda[] as part of the lambda expression but will treat it as an opaque function object, so it there is no extra evaluation round for binding the actual arguments of the outer lambda expression to the local variables. Still I'm sure you can come out with a protocol to do that without requiring the extra round to be shown to the user.
The premise is flawed. Your assumptions are wrong. This is not the reason why there needs to be an extra evaluation round. In fact, the "extra round" is never shown to the user! It happens inside the phoenix function. Look: for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] ) Do you see an extra function application there? No.
Here's the crucial difference (using BLL) highlighting the difference:
{ int x = 5; int r = bind(_1, _2)(unlambda(_1), x); BOOST_TEST(x == 5); }
{ int x = 5; int r = bind(_1, _2)(protect(_1)(), x); BOOST_TEST(x == 5); }
Notice that protect *requires* the additional function application:
protect(_1)()
I understand the difference, but what buys us? What is the advantage? It feels a bit like an internal detail leaking...
Ask Jaakko. It's his interface. I can't speak for him. I'm only saying that it is not the same and you can't replace the one for the other. I'm also saying that it is the "protect" model that Phoenix is adopting, not unlambda. Hence, the misconception and misunderstanding. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
Giovanni Piero Deretta wrote:
No, that is not the "unlambda" semantics. There needs to be 2 function application there: 1) the one that substitutes the stl container for _1 (the leftmost _1) and 2) the one that substitutes the container's element for _1 (the rightmost _1). The key point here is that phx.lambda (and BLL protect), *returns a lambda-functor that returns a lambda-functor*. unlambda OTOH simply returns a plain functor (non-actor). A plain functor can only do one function application (bear in mind that this is phoenix for_each (lazy), not std::for_each (eager)).
Ok, follow me:
let 'f' me an unary function object, one suitable as a parameter to for_each: Am I right that the following calls should work and apply every element of some range to 'f'?
phx::for_each(_1, f)(some_range);
No. Not unless you bind f.
Ok, I think this is it! This is the main misunderstanding about phx::for_each and all phoenix functions that take in other functions. All phoenix expressions must be a legitimate phoenix actor (following the actor concept). That is obvious in other contexts. For example, given a plain function object f: struct f { int operator()(int i); }; you can't just write: f(_1) + val(123) // error f can't take a _1 argument you need to either: 1) bind it 2) make a phoenix function out of it So: phx::for_each(_1, f)(some_range); is an error. f is not an actor. Hence, make it one. Let's use bind: phx::for_each(_1, bind(f, _1))(some_range); now, that is still in error: 1) The placeholders are eagerly substituted. 2) After substituting _1 the result of the bind: f(some_range) has the wrong call. So, you'll want to protect it. In phoenix, we use "lambda": phx::for_each(_1, lambda[bind(f, _1)])(some_range); Assuming phoenix had "unlambda" (which BTW is very easy to do), We're back to square one. Phoenix does not allow arbitrary functions/function objects as the function argument to for_each (or any phoenix function that takes in a higher-order function. It must be a phoenix actor. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Oct 2, 2008 at 1:10 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
No, that is not the "unlambda" semantics. There needs to be 2 function application there: 1) the one that substitutes the stl container for _1 (the leftmost _1) and 2) the one that substitutes the container's element for _1 (the rightmost _1). The key point here is that phx.lambda (and BLL protect), *returns a lambda-functor that returns a lambda-functor*. unlambda OTOH simply returns a plain functor (non-actor). A plain functor can only do one function application (bear in mind that this is phoenix for_each (lazy), not std::for_each (eager)).
Ok, follow me:
let 'f' me an unary function object, one suitable as a parameter to for_each: Am I right that the following calls should work and apply every element of some range to 'f'?
phx::for_each(_1, f)(some_range);
No. Not unless you bind f.
OK, I'm really really missing something: #include <iostream> #include <vector> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/home/phoenix/stl.hpp> #include <boost/spirit/include/phoenix_operator.hpp> using namespace boost::phoenix; struct foo { typedef void result_type; void operator()(int x) const{ std::cout << x << std::endl; } }; namespace px = boost::phoenix; int main() { std::vector<int> r(10, 1); foo f; px::for_each(px::arg_names::arg1, f)(r); return 0; } This compiles just fine and prints 1 ten times.... I do not need bind to use 'f', it is a perfectly fine unary function object. Phoenix has no business messing with it :)
Ok, now 'f' is unlambda(std::cout << _1 << std::endl) (assuming phoenix had unlambda with the same semantics of boost::lambda::unlambda. Isn't the previous example still supposed to work? From phoenix point of view, the internal lambda expression is masked so it is treated as any other function object.
No it won't work, unless you bind it. An arbitrary function object is not lazy -- it is no different than an ordinary function.
which is a perfectly good argument to for_each.
f must be a lambda function, not an ordinary function (or function object). And, in addition to that, it must be lambda function that returns a lambda function.
No on both counts. The above example compiles just fine... I feel that you are looking for complexity were there isn't ... I think that phoenix needs to know about functional arguments only when it need to do placeholder substitution on variable initialization.
The problem is of course that this prevent binding local lambda variables to placeholders of the outer lambda expression: phoenix will not recongnize the result of lambda[] as part of the lambda expression but will treat it as an opaque function object, so it there is no extra evaluation round for binding the actual arguments of the outer lambda expression to the local variables. Still I'm sure you can come out with a protocol to do that without requiring the extra round to be shown to the user.
The premise is flawed. Your assumptions are wrong. This is not the reason why there needs to be an extra evaluation round. In fact, the "extra round" is never shown to the user! It happens inside the phoenix function. Look:
for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] )
Do you see an extra function application there? No.
As I said elsewere, the extra round is hidden when lambda is used to protect a nested expression, but it shows when used a top level: lambda[ for_each(arg1, lambda(_a = arg2)[push_back(arg1, _a)])] () (r, i); There is really really no need for the extra '()' there. There are no local variables in the outer lambda and even if there were, the user can initialize them with lambda(/* init here*/)[...]
Here's the crucial difference (using BLL) highlighting the difference:
{ int x = 5; int r = bind(_1, _2)(unlambda(_1), x); BOOST_TEST(x == 5); }
{ int x = 5; int r = bind(_1, _2)(protect(_1)(), x); BOOST_TEST(x == 5); }
Notice that protect *requires* the additional function application:
protect(_1)()
I understand the difference, but what buys us? What is the advantage? It feels a bit like an internal detail leaking...
Ask Jaakko. It's his interface. I can't speak for him. I'm only saying that it is not the same and you can't replace the one for the other. I'm also saying that it is the "protect" model that Phoenix is adopting, not unlambda. Hence, the misconception and misunderstanding.
Yes, and that is what I'm lobbying to change :) -- gpd

Giovanni Piero Deretta wrote:
On Thu, Oct 2, 2008 at 1:10 PM, Joel de Guzman
OK, I'm really really missing something:
#include <iostream> #include <vector> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/home/phoenix/stl.hpp> #include <boost/spirit/include/phoenix_operator.hpp>
using namespace boost::phoenix;
struct foo { typedef void result_type; void operator()(int x) const{ std::cout << x << std::endl; } };
namespace px = boost::phoenix;
int main() { std::vector<int> r(10, 1); foo f; px::for_each(px::arg_names::arg1, f)(r); return 0;
}
This compiles just fine and prints 1 ten times.... I do not need bind to use 'f', it is a perfectly fine unary function object. Phoenix has no business messing with it :)
Aha! You've just uncovered an undocumented feature that I was working on. In phoenix1 and in an experimental version of the scopes, this is actually valid: for_each(_1, val(f))(r); Phx always captures by value, so f is essentially val(f) and val(f)() *is* the f itself. Notice the extra nullary function application. (aside: I'm actually surprised that this feature got in. Some tests by Dan Marsden even takes advantage of it). :-) You must be smiling now imagining me slapping my head! :-)
I understand the difference, but what buys us? What is the advantage? It feels a bit like an internal detail leaking... Ask Jaakko. It's his interface. I can't speak for him. I'm only saying that it is not the same and you can't replace the one for the other. I'm also saying that it is the "protect" model that Phoenix is adopting, not unlambda. Hence, the misconception and misunderstanding.
Yes, and that is what I'm lobbying to change :)
I hear ya. But if you just be patient and try to read my plans on pxh.lambda that initiated this discussion more carefully, I actually have something that somehow unifies all these (including the undocumented val(f) you got rolling). Listen, I'm not saying that what you are saying is wrong. I'm just saying that that is not the (current) design. Finally, I'm very eager to hear Jaakko's take on this. More inputs, the better. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Oct 2, 2008 at 3:31 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
On Thu, Oct 2, 2008 at 1:10 PM, Joel de Guzman
OK, I'm really really missing something:
#include <iostream> #include <vector> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/home/phoenix/stl.hpp> #include <boost/spirit/include/phoenix_operator.hpp>
using namespace boost::phoenix;
struct foo { typedef void result_type; void operator()(int x) const{ std::cout << x << std::endl; } };
namespace px = boost::phoenix;
int main() { std::vector<int> r(10, 1); foo f; px::for_each(px::arg_names::arg1, f)(r); return 0;
}
This compiles just fine and prints 1 ten times.... I do not need bind to use 'f', it is a perfectly fine unary function object. Phoenix has no business messing with it :)
Aha! You've just uncovered an undocumented feature that I was working on. In phoenix1 and in an experimental version of the scopes, this is actually valid:
for_each(_1, val(f))(r);
Phx always captures by value, so f is essentially val(f) and val(f)() *is* the f itself. Notice the extra nullary function application.
(aside: I'm actually surprised that this feature got in. Some tests by Dan Marsden even takes advantage of it).
*scratches head* Is it really undocumented? Look at http://tinyurl.com/4lnlh3 , the section about Values " 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)) " Besides, this is the behavior one would expect (as it mimics std::bind).
:-) You must be smiling now imagining me slapping my head! :-)
:) Anyways, from your last post, I see that we basically agree on lambda[] behavior, so I'll stop here. -- gpd

Giovanni Piero Deretta wrote:
On Thu, Oct 2, 2008 at 3:31 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
*scratches head*
Is it really undocumented? Look at http://tinyurl.com/4lnlh3 , the section about Values
" 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)) "
Besides, this is the behavior one would expect (as it mimics std::bind).
You are probably right. Anyway, there's more to it than that. For example, there is also the plan to have explicit: val(lambda-expression) be used as the phoenix equivalent of unlambda(lambda-expression) Behind the scenes, there's some work being done to make this happen. I don't think I've committed such code. I'm not quite sure about it.
:-) You must be smiling now imagining me slapping my head! :-)
:)
Anyways, from your last post, I see that we basically agree on lambda[] behavior, so I'll stop here.
Cool! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Giovanni Piero Deretta wrote:
As I said elsewere, the extra round is hidden when lambda is used to protect a nested expression, but it shows when used a top level:
lambda[ for_each(arg1, lambda(_a = arg2)[push_back(arg1, _a)])] () (r, i);
There is really really no need for the extra '()' there. There are no local variables in the outer lambda and even if there were, the user can initialize them with lambda(/* init here*/)[...]
Ok, this I agree. Again, if you read my earlier post on the plan to unify these, this is actually my intention: ... Oh my, there's a lot of discussion I can't find that snippet of information. Anyway, it has something to do about using the "let" semantics be applied to "lambda" only on the top level. I think it will work with the lambda syntax and behavior you sought for. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Oct 2, 2008 at 3:41 PM, Joel de Guzman <joel@boost-consulting.com>wrote:
Giovanni Piero Deretta wrote:
As I said elsewere, the extra round is hidden when lambda is used to
protect a nested expression, but it shows when used a top level:
lambda[ for_each(arg1, lambda(_a = arg2)[push_back(arg1, _a)])] () (r, i);
There is really really no need for the extra '()' there. There are no local variables in the outer lambda and even if there were, the user can initialize them with lambda(/* init here*/)[...]
Ok, this I agree.
Hmm, I think this could complicate the understanding. It seems Giovanni's complaint is because he sees lambda[] as an introducer for a lambda expression, but this is in contradiction with the fact that expressions within the lambda itself could be eagerly evaluated if not properly wrapped (and introduction of optional lazy functions could even worse the problem). I fear an user could think that lambda[ std::cout<<"Hello world" ] is actually constructing a delayed invocation (as in C++0x), while it is not, and it cannot be. On the other hand, if lambda[] is reserved as intended by Giovanni, what would be the syntax for creating a lazy function that returns a lazy function that returns a lazy function? We could handle differently the topmost lambda and the inner ones, but guessing the number of lambdas necessary to achieve what you want might be difficult. For the other requests, e.g. having lazy functions that capture by reference or const reference, I think a cast like syntax could be handy: capture<by_ref>(arg1+1) In this way, the way the arguments are captured can be changed not only at definition site, but also at call site. Corrado __________________________________________________________________________ dott. Corrado Zoccolo mailto:czoccolo@gmail.com PhD - Department of Computer Science - University of Pisa, Italy --------------------------------------------------------------------------

Corrado Zoccolo wrote:
On Thu, Oct 2, 2008 at 3:41 PM, Joel de Guzman <joel@boost-consulting.com>wrote:
Giovanni Piero Deretta wrote:
As I said elsewere, the extra round is hidden when lambda is used to
protect a nested expression, but it shows when used a top level:
lambda[ for_each(arg1, lambda(_a = arg2)[push_back(arg1, _a)])] () (r, i);
There is really really no need for the extra '()' there. There are no local variables in the outer lambda and even if there were, the user can initialize them with lambda(/* init here*/)[...]
Ok, this I agree.
Hmm, I think this could complicate the understanding. It seems Giovanni's complaint is because he sees lambda[] as an introducer for a lambda expression, but this is in contradiction with the fact that expressions within the lambda itself could be eagerly evaluated if not properly wrapped (and introduction of optional lazy functions could even worse the problem).
I fear an user could think that lambda[ std::cout<<"Hello world" ] is actually constructing a delayed invocation (as in C++0x), while it is not, and it cannot be.
On the other hand, if lambda[] is reserved as intended by Giovanni, what would be the syntax for creating a lazy function that returns a lazy function that returns a lazy function? We could handle differently the topmost lambda and the inner ones, but guessing the number of lambdas necessary to achieve what you want might be difficult.
For the other requests, e.g. having lazy functions that capture by reference or const reference, I think a cast like syntax could be handy: capture<by_ref>(arg1+1)
In this way, the way the arguments are captured can be changed not only at definition site, but also at call site.
Very good points. I somehow feel the same but couldn't articulate my thoughts well enough. Let's see Giovanni's answer to this one. I hope other folks would as well chime in on this crucial matter. Cheers, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman:
Oh my, there's a lot of discussion I can't find that snippet of information. Anyway, it has something to do about using the "let" semantics be applied to "lambda" only on the top level. I think it will work with the lambda syntax and behavior you sought for.
Not quite. The purpose of unlambda is to allow you to pass a lambda expression into a function that expects an ordinary function object and might use it as a part of another lambda expression. template<class F> void g( F f ) { h( bind( f, _2, _1 ) ); } int main() { g( _1 < _2 ); // fail g( unlambda( _1 < _2 ) ); // works } A top-level lambda[] that does let()[] will not work for this case.

Peter Dimov wrote:
Joel de Guzman:
Oh my, there's a lot of discussion I can't find that snippet of information. Anyway, it has something to do about using the "let" semantics be applied to "lambda" only on the top level. I think it will work with the lambda syntax and behavior you sought for.
Not quite.
The purpose of unlambda is to allow you to pass a lambda expression into a function that expects an ordinary function object and might use it as a part of another lambda expression.
template<class F> void g( F f ) { h( bind( f, _2, _1 ) ); }
int main() { g( _1 < _2 ); // fail g( unlambda( _1 < _2 ) ); // works }
A top-level lambda[] that does let()[] will not work for this case.
Yep, I'm keeping the behavior of protect, not unlambda. As I mentioned in my other post. val(_1 < _2) can probably be the unlambda behavior. BTW, has anyone realized that if I were to make phoenix, lambda, then lambda[ ... ] will be ambiguous with the namespace lambda? Argh! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman: ...
template<class F> void g( F f ) { h( bind( f, _2, _1 ) ); }
int main() { g( _1 < _2 ); // fail g( unlambda( _1 < _2 ) ); // works }
A top-level lambda[] that does let()[] will not work for this case.
Yep, I'm keeping the behavior of protect, not unlambda.
What is the current Phoenix way to make the above work?
As I mentioned in my other post. val(_1 < _2) can probably be the unlambda behavior.
This doesn't feel right to me. val(x)(...) returns x. val(_1 < _2)( 1, 2 ) ought to return _1 < _2. unlambda( _1 < _2 )( 1, 2 ) returns true.

Peter Dimov wrote:
Joel de Guzman: ...
template<class F> void g( F f ) { h( bind( f, _2, _1 ) ); }
int main() { g( _1 < _2 ); // fail g( unlambda( _1 < _2 ) ); // works }
A top-level lambda[] that does let()[] will not work for this case.
Yep, I'm keeping the behavior of protect, not unlambda.
What is the current Phoenix way to make the above work?
I don't think there's one, yet. Never had the need for it (at least not yet). unlambda is a low hanging fruit in any case.
As I mentioned in my other post. val(_1 < _2) can probably be the unlambda behavior.
This doesn't feel right to me. val(x)(...) returns x. val(_1 < _2)( 1, 2 ) ought to return _1 < _2. unlambda( _1 < _2 )( 1, 2 ) returns true.
Why do you need to write val(_1 < _2) and not just _1 < _2 ? Cheers, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman:
This doesn't feel right to me. val(x)(...) returns x. val(_1 < _2)( 1, 2 ) ought to return _1 < _2. unlambda( _1 < _2 )( 1, 2 ) returns true.
Why do you need to write val(_1 < _2) and not just _1 < _2 ?
I have no idea. I'm just saying that val( _1 < _2 ) already has a meaning that is not the same as _1 < _2.

AMDG Joel de Guzman wrote:
Yep, I'm keeping the behavior of protect, not unlambda. As I mentioned in my other post. val(_1 < _2) can probably be the unlambda behavior.
I don't think it's a good idea to overload val like this, giving it two different unrelated meanings. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Joel de Guzman wrote:
Yep, I'm keeping the behavior of protect, not unlambda. As I mentioned in my other post. val(_1 < _2) can probably be the unlambda behavior.
I don't think it's a good idea to overload val like this, giving it two different unrelated meanings.
I think you're probably right. For example, I use: val(_1) to convert the referene into a val. So, agreed. It does not make sense to overload the meaning of val. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] )
... I'm not an expert on modern FP, but the above lambda doesn't seem like a classic lambda (as in lambda calculus and Lisp) to me. Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form lambda( _x, _y )[ _x + _y ] where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).) Local state would look like lambda( _x, _a = 0 )[ _a += _x ] and one can also extend this to lambda( byval, ... ) and lambda( byref, ... ) to control the default capture behavior. I'd spell function application inside a lambda as apply( f, x ) and not as bind, leaving the latter as an alias for lambda[ apply ]. So \f \x f (f x) would be lambda( _f )[ lambda( _x ) [ apply( _f, apply( _f, _x ) ) ] ] Using the above example as a test for this theory:
for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] )
In lambda terms, it's something like \x,y for_each( x, \z push_back( z, y ) ) so (with lazy for_each and push_back): lambda( _x, _y )[ for_each( _x, lambda( _z )[ push_back( _z, _y ) ] ) ] This implies that a lambda[] must be able to access an outer scope. I wonder how could one do that. :-) The outer lambda should be able to do some term rewriting, I guess. I should also be able to spell that as: lambda( _x, _y )[ for_each( _x, lambda( _x )[ push_back( _x, _y ) ] ) ] with the two _x being properly scoped.

On Thu, Oct 2, 2008 at 8:58 PM, Peter Dimov <pdimov@pdimov.com> wrote:
for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] )
...
I'm not an expert on modern FP, but the above lambda doesn't seem like a classic lambda (as in lambda calculus and Lisp) to me.
Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form
lambda( _x, _y )[ _x + _y ]
where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).)
Oh yes please! Unfortunately I think that this would require major surgery of phoenix... -- gpd

AMDG Giovanni Piero Deretta wrote:
I'm not an expert on modern FP, but the above lambda doesn't seem like a classic lambda (as in lambda calculus and Lisp) to me.
Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form
lambda( _x, _y )[ _x + _y ]
where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).)
Oh yes please! Unfortunately I think that this would require major surgery of phoenix...
+1 from me for that syntax. I don't think that it will actually require major surgery after all. It really just requires a small adjustment of the environment. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Giovanni Piero Deretta wrote:
I'm not an expert on modern FP, but the above lambda doesn't seem like a classic lambda (as in lambda calculus and Lisp) to me.
Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form
lambda( _x, _y )[ _x + _y ]
where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).)
Oh yes please! Unfortunately I think that this would require major surgery of phoenix...
+1 from me for that syntax.
I don't think that it will actually require major surgery after all. It really just requires a small adjustment of the environment.
Hmmm... I don't think Phoenix requires a major surgery for this. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
Steven Watanabe wrote:
AMDG
Giovanni Piero Deretta wrote:
I'm not an expert on modern FP, but the above lambda doesn't seem like a classic lambda (as in lambda calculus and Lisp) to me.
Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form
lambda( _x, _y )[ _x + _y ]
where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).)
Oh yes please! Unfortunately I think that this would require major surgery of phoenix...
+1 from me for that syntax.
I don't think that it will actually require major surgery after all. It really just requires a small adjustment of the environment.
Hmmm... I don't think Phoenix requires a major surgery for this.
Ok, Easy. It's just a matter of filtering the /bare/ variables in the lambda declaration (using fusion! hurray) and transforming the list of declarations (again fusion!) such that each unassigned variable takes an argument. This: lambda( _x, _y, _z = 123 )[ ... ] will be transformed to this: lambda( _x = _1, _y = _2, _z = 123 )[ ... ] I wonder though if it's a good idea to separate the signature from the locals: lambda( _x, _y )[ let( _z = 123 )[ ... ] ] seems to be more "idiomatic"? No? In the last case, lambda just takes in the signature. Let "let" do the locals. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

AMDG Joel de Guzman wrote:
I wonder though if it's a good idea to separate the signature from the locals:
lambda( _x, _y )[ let( _z = 123 )[ ... ] ]
seems to be more "idiomatic"? No?
In the last case, lambda just takes in the signature. Let "let" do the locals.
Agreed. Unless we mimic C++ default arguments and make it so that lambda( _x, _y, _z = 123 )[ ... ] can be called with either 2 or three arguments, using 123 for _z if only two arguments are passed. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Joel de Guzman wrote:
I wonder though if it's a good idea to separate the signature from the locals:
lambda( _x, _y )[ let( _z = 123 )[ ... ] ]
seems to be more "idiomatic"? No?
In the last case, lambda just takes in the signature. Let "let" do the locals.
Agreed. Unless we mimic C++ default arguments and make it so that lambda( _x, _y, _z = 123 )[ ... ] can be called with either 2 or three arguments, using 123 for _z if only two arguments are passed.
Hmmm, we can support default arguments actually. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman: ...
This:
lambda( _x, _y, _z = 123 )[ ... ]
will be transformed to this:
lambda( _x = _1, _y = _2, _z = 123 )[ ... ]
I wonder though if it's a good idea to separate the signature from the locals:
lambda( _x, _y )[ let( _z = 123 )[ ... ] ]
seems to be more "idiomatic"? No?
Under my mental model of the "new lambda", these two are not the same. _z = 123 in the lambda initializes _z to 123 once when the lambda is defined; let _z = 123 declares _z to be 123 each time the lambda is called. That is, the outer _z is a member variable, the inner _z is a local temporary. So, if we return to my generator example that was to yield 1, 2, 3 on successive calls, it would be spelled lambda( _a = 0 )[ ++_a ] as I first expected. Incidentally, you might consider supporting a scopeless let (if it doesn't already work): lambda(_x, _y)[ let( _z = _x + _y ), _z * _z ] analogous to a C++ local variable: auto _z = _x + _y; return _z * _z; and maybe even dispense with the let at all: lambda(_x, _y)[ _z = _x + _y, _z * _z ] although this has the usual drawback with being ambiguous with an assignment to an outer-scope _z: lambda( _x, _y, _z = 0 )[ _z = _x + _y, _z * _z ]

Peter Dimov wrote:
Joel de Guzman: ...
This:
lambda( _x, _y, _z = 123 )[ ... ]
will be transformed to this:
lambda( _x = _1, _y = _2, _z = 123 )[ ... ]
I wonder though if it's a good idea to separate the signature from the locals:
lambda( _x, _y )[ let( _z = 123 )[ ... ] ]
seems to be more "idiomatic"? No?
Under my mental model of the "new lambda", these two are not the same. _z = 123 in the lambda initializes _z to 123 once when the lambda is defined; let _z = 123 declares _z to be 123 each time the lambda is called. That is, the outer _z is a member variable, the inner _z is a local temporary.
So, if we return to my generator example that was to yield 1, 2, 3 on successive calls, it would be spelled
lambda( _a = 0 )[ ++_a ]
as I first expected.
Hrm. I'm not so sure about this one. I think I prefer Steven's suggestion to follow C++ lambda in that _a = 0 mimicking default arguments.
Incidentally, you might consider supporting a scopeless let (if it doesn't already work):
lambda(_x, _y)[ let( _z = _x + _y ), _z * _z ]
Nice one!
analogous to a C++ local variable:
auto _z = _x + _y; return _z * _z;
and maybe even dispense with the let at all:
lambda(_x, _y)[ _z = _x + _y, _z * _z ]
Hmm. Might be tough.
although this has the usual drawback with being ambiguous with an assignment to an outer-scope _z:
lambda( _x, _y, _z = 0 )[ _z = _x + _y, _z * _z ]
Ok, all good points. Let me start and I'll see what can be done. I think all the ingredients are already present. It's just a matter of having the right behavior. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Fri, Oct 3, 2008 at 2:25 AM, Peter Dimov <pdimov@pdimov.com> wrote:
Incidentally, you might consider supporting a scopeless let (if it doesn't already work):
lambda(_x, _y)[ let( _z = _x + _y ), _z * _z ]
analogous to a C++ local variable:
auto _z = _x + _y; return _z * _z;
Nice.
and maybe even dispense with the let at all:
lambda(_x, _y)[ _z = _x + _y, _z * _z ]
although this has the usual drawback with being ambiguous with an assignment to an outer-scope _z:
lambda( _x, _y, _z = 0 )[ _z = _x + _y, _z * _z ]
No please, I hate this in python. Let 'let' be (no pun intended). BTW, Joel, if Phoenix can do this easily, major kudos! -- gpd

Giovanni Piero Deretta: ...
lambda(_x, _y)[ _z = _x + _y, _z * _z ]
No please, I hate this in python. Let 'let' be (no pun intended).
Eh. How about this one: lambda(_x, _y)[ let. _z = _x + _y, _z * _z ] I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.

On Fri, Oct 3, 2008 at 6:44 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Giovanni Piero Deretta: ...
lambda(_x, _y)[ _z = _x + _y, _z * _z ]
No please, I hate this in python. Let 'let' be (no pun intended).
Eh. How about this one:
lambda(_x, _y)[ let. _z = _x + _y, _z * _z ]
This is quite nice.
I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.
Hum, the same lambda()[] could means two different things when used when in different contextes... it seems pretty bad to me. And with 'auto' around the corner, it is won't be hard to reuse a lambda expression. -- gpd

AMDG Peter Dimov wrote:
Eh. How about this one:
lambda(_x, _y)[ let. _z = _x + _y, _z * _z ]
I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.
Doesn't that imply that _a, _b, ... have to be enumerated in the definition of let? I like to have the possibility of defining new local variable names. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Peter Dimov wrote:
Eh. How about this one:
lambda(_x, _y)[ let. _z = _x + _y, _z * _z ]
I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.
Doesn't that imply that _a, _b, ... have to be enumerated in the definition of let?
Not sure I understand.
I like to have the possibility of defining new local variable names.
Oh sure you can define new names in Phoenix: actor<local_variable<Key> > E.g: struct size_key; actor<local_variable<size_key> > size; Is that what you mean? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

AMDG Joel de Guzman wrote:
lambda(_x, _y)[ let. _z = _x + _y, _z * _z ]
I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.
Doesn't that imply that _a, _b, ... have to be enumerated in the definition of let?
Not sure I understand.
let. _z ^ let must be an object that has a member called _z. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Joel de Guzman wrote:
lambda(_x, _y)[ let. _z = _x + _y, _z * _z ]
I think that the implicit let will be much less of an issue in a lambda context than it is in Python (or Javascript), though.
Doesn't that imply that _a, _b, ... have to be enumerated in the definition of let?
Not sure I understand.
let. _z ^
let must be an object that has a member called _z.
Right. Now I understand. Now I also understand why you want to be able to name the locals. Pardon me for being slow. It's been an overwhelming review. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Peter Dimov wrote:
Now that I've seen what Phoenix can do, I think that, were I to design a Boost.Lambda2, I'd probably go with a classic lambda of the form
lambda( _x, _y )[ _x + _y ]
where the inner _x + _y is not a function object, and it is the lambda[] that turns it into one. (That is, the evaluation of an inner expression would be done with eval(expr, args...) and not with expr(args...).)
That is actally what's happening internally already.
Local state would look like
lambda( _x, _a = 0 )[ _a += _x ]
and one can also extend this to lambda( byval, ... ) and lambda( byref, ... ) to control the default capture behavior.
Interesting. I'd spell function
application inside a lambda as apply( f, x ) and not as bind, leaving the latter as an alias for lambda[ apply ].
Hmm, right.
So \f \x f (f x) would be
lambda( _f )[ lambda( _x ) [ apply( _f, apply( _f, _x ) ) ] ]
Using the above example as a test for this theory:
for_each(arg1, lambda(_a = arg2) [ push_back(arg1, _a) ] )
In lambda terms, it's something like
\x,y for_each( x, \z push_back( z, y ) )
so (with lazy for_each and push_back):
lambda( _x, _y )[ for_each( _x, lambda( _z )[ push_back( _z, _y ) ] ) ]
This implies that a lambda[] must be able to access an outer scope. I wonder how could one do that. :-) The outer lambda should be able to do some term rewriting, I guess.
Phoenix already does that. See let visibility: http://tinyurl.com/3qq2bl It's one of the early requirements. I'm quite happy with it. Hah, those were one of the sleepless coding nights. Example from the doc: let(_x = 1, _y = ", World") [ // _x here is an int: 1 let(_x = "Hello") // hides the outer _x [ cout << _x << _y // prints "Hello, World" ] ] anything you can do with "let", you can do with "lambda".
I should also be able to spell that as:
lambda( _x, _y )[ for_each( _x, lambda( _x )[ push_back( _x, _y ) ] ) ]
with the two _x being properly scoped.
Yep. Phoenix can do that. A local variable may hide an outer local variable. Here, we just reuse the locals for arguments to the lambda as well. So, in current terms, this: lambda( _x, _y )[ _x + _y ] is just this: lambda( _x = _1, _y = _2 )[ _x + _y ] Very cool suggestion, Peter! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

AMDG Joel de Guzman wrote:
Yep. Phoenix can do that. A local variable may hide an outer local variable. Here, we just reuse the locals for arguments to the lambda as well. So, in current terms, this:
lambda( _x, _y )[ _x + _y ]
is just this:
lambda( _x = _1, _y = _2 )[ _x + _y ]
Am I misunderstanding something? I thought that this would give lambda( _x = _1, _y = _2 )[ _x + _y ] (1, 2)() == 3 instead of lambda( _x = _1, _y = _2 )[ _x + _y ] ()(1, 2) == 3
Very cool suggestion, Peter!
I don't think it is quite the same if you use an arbitrary expression instead of _x + _y. For instance, what should this mean: lambda(_x, _y) [ _x + _y + _1 ] I'm inclined to think that _1, &c. should be reserved for the top level placeholders. This allows each placeholder to have a unique meaning in the full lambda expression, rather than having different placeholders refer to the same object and having the same placeholder refer to multiple objects. lambda(_o = _1) [ let(_x = _1, _y = _2) [ _x + _y + _o ] ] In Christ, Steven Watanabe

Steven Watanabe:
Joel de Guzman wrote:
Yep. Phoenix can do that. A local variable may hide an outer local variable. Here, we just reuse the locals for arguments to the lambda as well. So, in current terms, this:
lambda( _x, _y )[ _x + _y ]
is just this:
lambda( _x = _1, _y = _2 )[ _x + _y ]
Am I misunderstanding something? I thought that this would give lambda( _x = _1, _y = _2 )[ _x + _y ] (1, 2)() == 3 instead of lambda( _x = _1, _y = _2 )[ _x + _y ] ()(1, 2) == 3
Under the model I have in mind: lambda( _x, _y )[ _x + _y ] ( 1, 2 ) == 3 That is, lambda is not lazy, and it doesn't compose further. lambda( _x )[ _x ] + _1 doesn't compile; there's no operator+ taking a lambda.
I don't think it is quite the same if you use an arbitrary expression instead of _x + _y. For instance, what should this mean:
lambda(_x, _y) [ _x + _y + _1 ]
If we're allowed to not think about backward compatibility, I'd say that _1 would no longer exist. Not even at top level.

Peter Dimov wrote:
Steven Watanabe:
Joel de Guzman wrote:
Yep. Phoenix can do that. A local variable may hide an outer local variable. Here, we just reuse the locals for arguments to the lambda as well. So, in current terms, this:
lambda( _x, _y )[ _x + _y ]
is just this:
lambda( _x = _1, _y = _2 )[ _x + _y ]
Am I misunderstanding something? I thought that this would give lambda( _x = _1, _y = _2 )[ _x + _y ] (1, 2)() == 3 instead of lambda( _x = _1, _y = _2 )[ _x + _y ] ()(1, 2) == 3
Under the model I have in mind:
lambda( _x, _y )[ _x + _y ] ( 1, 2 ) == 3
That is, lambda is not lazy, and it doesn't compose further.
lambda( _x )[ _x ] + _1
doesn't compile; there's no operator+ taking a lambda.
Again, there's a problem with this behavior and the higher-order argument ala for_each. But maybe not. I'm starting to investigate. There was a time that this was allowed: phx::for_each(_1, std::cout << _1 << std::endl) (vec) The f is an implicit lambda. Not saying that this is good, but just to show that it's possible to detect the scope of the _1 on the left and on the right. Explicit lambdas would be the same, me thinks.
I don't think it is quite the same if you use an arbitrary expression instead of _x + _y. For instance, what should this mean:
lambda(_x, _y) [ _x + _y + _1 ]
If we're allowed to not think about backward compatibility, I'd say that _1 would no longer exist. Not even at top level.
Right! _1 would not make sense because essentially all the arguments are declared already in the lambda declarator (_x, _y). Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Peter Dimov wrote:
Joel de Guzman:
Maybe you want:
let(_a = 0)[ ++_a ]
Maybe I do. :-)
No, I don't. This compiles, but always returns 1 when invoked. I want the equivalent of:
struct _F { int _a;
_F(): _a( 0 ) {}
int operator()() { return ++_a; } };
Oh right. A stateful variable. In the POV of the op() it's not really a local variable, right? A local variable is more like: struct _F { int operator()() { int _a = 0; return ++_a; } }; I don't think the locals are what you want here. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

- \ \ double - /\ f . /\ x. f(f x) - / \ / \
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ] ?
FWIW, the above doesn't work for me. What is the proper Phoenix way to express this double lambda? PS. <boost/function.hpp> and Phoenix don't play together on VC 7.1. C:\boost\trunk\boost\spirit\home\phoenix\core\detail\function_eval.hpp(107) : error C2027: use of undefined type 'boost::function' C:\boost\trunk\boost\function\function_base.hpp(99) : see declaration of 'boost::function'

Peter Dimov wrote:
- \ \ double - /\ f . /\ x. f(f x) - / \ / \
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ] ?
FWIW, the above doesn't work for me. What is the proper Phoenix way to express this double lambda?
Here's an example: #include <iostream> #include <boost/detail/lightweight_test.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_function.hpp> #include <boost/spirit/include/phoenix_scope.hpp> using namespace boost::phoenix; using namespace boost::phoenix::arg_names; struct sqr_impl { template <typename Arg> struct result { typedef Arg type; }; template <typename Arg> Arg operator()(Arg n) const { return n * n; } }; function<sqr_impl> sqr; struct ffx_impl { template <typename ArgF, typename ArgX> struct result { typedef ArgX type; }; template <typename ArgF, typename ArgX> ArgX operator()(ArgF f, ArgX arg2) const { ArgX x = f(arg2); return f(x); } }; function<ffx_impl> ffx; int main() { std::cout << "Square of " << 5.0 << " is " << sqr(5)() << std::endl; std::cout << "Double Square of " << 5 << " is " << ffx(lambda[sqr(_1)], 5.0)() << std::endl; std::cout << "Double Double Square of " << 5 << " is " << ffx(lambda[ ffx(lambda[sqr(_1)], _1) ], 5.0 )() << std::endl; return 0; } This was first discussed in a post by Joel Young (2002!): http://lists.boost.org/Archives/boost/2002/03/27181.php after my naive initial response, I got something like: http://lists.boost.org/Archives/boost/2002/03/27250.php which is a template function that returns a function (doub). Notes: * Here, lambda[..] is getting rather unwieldy. I had an earlier version with implicit lambdas. With that, you write Double Double Square expression more succinctly as: ffx(ffx(sqr(_1), _1), 5.0) * Perhaps there's a terser way similar to your suggestion without using phoenix function. I'll investigate on it. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman:
std::cout << "Double Square of " << 5 << " is " << ffx(lambda[sqr(_1)], 5.0)() << std::endl;
This is not quite what I was after. As I understood your original problem, we are looking for a construct lflx such that: lflx( f ) yields a function ffx such that ffx( x ) yields f( f( x ) ). In other words, we want lflx( sqr )( 5.0 ) to give us sqr(sqr(5.0)). (The case where f and x are given at the same time is so easy that even boost::bind can do it.) I was also trying to express this double lambda lflx as a Phoenix expression: auto lflx = <phoenix expression here>; My original attempt: lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ] made sense to me, and I still don't understand why it doesn't work. Maybe if we start from something simpler I'd be able to find my error. What is the Phoenix way to take a binary function f( x, y ) and construct an unary function lxly for which lxly( x ) returns a unary function ly such that ly( y ) returns f( x, y )? (Classic curry, in other words.) I'd have expected lambda( _x = _1 )[ bind( f, _x, _1 ) ]

AMDG Peter Dimov wrote:
My original attempt:
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ]
made sense to me, and I still don't understand why it doesn't work.
I think it ought to work and I think I understand why it doesn't work. In the bind statement, if the function object is a reference it does not strip the reference off before accessing the nested ::template result<...>::type Here is a reduced test case #include <boost/spirit/home/phoenix/core.hpp> #include <boost/spirit/home/phoenix/bind.hpp> using namespace boost::phoenix; using namespace arg_names; struct square { template<class T> struct result { typedef T type; }; template<class T> T operator()(const T& t) const { return(t * t); } }; int main() { square s; double x = 2.0; double result = bind(ref(s), _1)(x); } In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Peter Dimov wrote:
My original attempt:
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ]
made sense to me, and I still don't understand why it doesn't work.
I think it ought to work and I think I understand why it doesn't work.
In the bind statement, if the function object is a reference it does not strip the reference off before accessing the nested ::template result<...>::type
Thanks Steven! I'm in a crashed state now. I'll look into it tomorrow. ( Wow, such intelligent people. Amazing! I'm honestly overwhelmed :P ) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Steven Watanabe wrote:
AMDG
Peter Dimov wrote:
My original attempt:
lambda( _f = _1 )[ bind( _f, bind( _f, _1 ) ) ]
made sense to me, and I still don't understand why it doesn't work.
I think it ought to work and I think I understand why it doesn't work.
In the bind statement, if the function object is a reference it does not strip the reference off before accessing the nested ::template result<...>::type
Here is a reduced test case
Fixed. Thanks again, Steven. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel wrote:
Steven Watanabe wrote:
In the bind statement, if the function object is a reference it does not strip the reference off before accessing the nested ::template result<...>::type
Fixed. Thanks again, Steven.
BTW, this fix (r49118) closes trac bug #2246 ( https://svn.boost.org/trac/boost/ticket/2246 ). Thanks, François

Peter Dimov wrote:
Joel de Guzman:
std::cout << "Double Square of " << 5 << " is " << ffx(lambda[sqr(_1)], 5.0)() << std::endl;
This is not quite what I was after. As I understood your original problem, we are looking for a construct lflx such that:
lflx( f )
yields a function ffx such that
ffx( x )
yields f( f( x ) ).
In other words, we want
lflx( sqr )( 5.0 ) to give us sqr(sqr(5.0)).
Sure. Like this: ffx(lambda[sqr(_1)], _1)(i5) // pardon no rvalue (yet) ? Cheers, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Peter Dimov wrote:
PS. <boost/function.hpp> and Phoenix don't play together on VC 7.1.
C:\boost\trunk\boost\spirit\home\phoenix\core\detail\function_eval.hpp(107) : error C2027: use of undefined type 'boost::function'
C:\boost\trunk\boost\function\function_base.hpp(99) : see declaration of 'boost::function'
Thanks for spotting. Fixed. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Eric Niebler:
Lambda has some quirks that it would be best to leave behind.
I agree, but I suspect that we don't agree on the specific quirks to be left behind. The unary & is on the top of my list. &x should never be overloaded, IMHO. Yes, we do have addressof. I'd still have gone with addr(_1) instead. The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
I support Joel's approach of deprecating the old lambda interface and migrating folks to phoenix.
I've always thought that the plan was for Lambda and Phoenix to merge one day. Apart from that, I'm not a Lambda user, so I don't have an opinion. :-)

Peter Dimov wrote:
Eric Niebler:
Lambda has some quirks that it would be best to leave behind.
I agree, but I suspect that we don't agree on the specific quirks to be left behind.
The unary & is on the top of my list. &x should never be overloaded, IMHO. Yes, we do have addressof. I'd still have gone with addr(_1) instead.
<offtopic> I've been on the fence about this one in Proto. By default, Proto overloads unary operator&, but with a twist: a unary operator& expression tree node is implicitly convertible to a pointer to its child. That means stuff like "arg<1> const *p1 = &_1;" actually work, but not in the obvious way. Proto also gives you the ability to turn off any of Proto's operator overloads within a domain by defining the grammar of that domain. </offtopic>
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
I support Joel's approach of deprecating the old lambda interface and migrating folks to phoenix.
I've always thought that the plan was for Lambda and Phoenix to merge one day.
That used to be the plan, long ago before Joel came to fully appreciate the subtle differences between the two.
Apart from that, I'm not a Lambda user, so I don't have an opinion. :-)
Even your non-opinions are valuable. :-) -- Eric Niebler BoostPro Computing http://www.boostpro.com

AMDG Eric Niebler wrote:
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
what about a nullary lambda: vector<int> v1, v2; (ref(v1) = ref(v2))(); ? In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Eric Niebler wrote:
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
what about a nullary lambda:
vector<int> v1, v2;
(ref(v1) = ref(v2))();
Yikes! Yeah :( Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
Steven Watanabe wrote:
AMDG
Eric Niebler wrote:
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
what about a nullary lambda:
vector<int> v1, v2;
(ref(v1) = ref(v2))();
Yikes! Yeah :(
It actually doesn't have to be a problem. Imagine: template<class T> struct actor { // non-const, does assignment actor & operator=(actor const &); // non-const assignment // const, builds an expression template actor</implementation-defined/> const operator=(actor const &) const; }; And then all the operators that build lambda expressions (e.g. phoenix::ref) return const rvalues. So an expression like: (ref(v1) = ref(v2))() would build an expression template, without having to sacrifice Assignability. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Tue, Sep 30, 2008 at 3:57 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Eric Niebler wrote:
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
what about a nullary lambda:
vector<int> v1, v2;
(ref(v1) = ref(v2))();
If phoenix required every lambda to be 'fenced' with lambda[] or something simlar, operator= would be a non problem: all the parts of a lambda would overload operator= to return an expression template, except for the function object returned by lambda[], which would be a plain function object (plus I guess extra facilities to set the internal local variables). The same is also true for operator&. -- gpd

Eric Niebler wrote:
Peter Dimov wrote:
Eric Niebler:
The other thorny issue is that lambda expressions aren't Assignable, because their operator= creates a new lambda exression instead. This might well be unfixable.
We could make lambdas Assignable by defining the ordinary assignment operator when the rhs has the same type as the lhs. That would rule out strange lambdas like "_1 = _1" , but I don't see that as a huge loss.
I think that's a good compromise.
I support Joel's approach of deprecating the old lambda interface and migrating folks to phoenix.
I've always thought that the plan was for Lambda and Phoenix to merge one day.
That used to be the plan, long ago before Joel came to fully appreciate the subtle differences between the two.
Apart from that, I'm not a Lambda user, so I don't have an opinion. :-)
Even your non-opinions are valuable. :-)
Peter, you rock! I highly value all your opinions. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Peter Dimov wrote:
Eric Niebler:
Lambda has some quirks that it would be best to leave behind.
I agree, but I suspect that we don't agree on the specific quirks to be left behind.
The unary & is on the top of my list. &x should never be overloaded, IMHO. Yes, we do have addressof. I'd still have gone with addr(_1) instead.
Let's put this to the vote too. I'm a fence sitter in this case: Allow & to be overloaded: +0 Provide explicit addr(_1): +1 Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

on Mon Sep 29 2008, "Peter Dimov" <pdimov-AT-pdimov.com> wrote:
Joel de Guzman:
Peter Dimov wrote: ...
Is it a goal of phoenix::bind to one day replace lambda::bind and boost::bind, being a superset of both, as well of std::bind?
lambda::bind, yes. std::bind cannot be replaced. boost::bind, too, IMO cannot be replaced, not in a long time, due to, as you said below, it works on more compilers.
It can be replaced on the compilers on which Phoenix works. It can also conform to the specification of std::bind, allowing people to move code back and forth.
phoenix::bind could dispatch to the current implementation of boost::bind for broken compilers. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Joel de Guzman: ...
I can definitely make sure that all those are supported. I supported the lambda tests in phoenix.
Unfortunately, the Lambda tests are incomplete, as they do not cover its most frequently encountered problems. Phoenix does seem to handle abstract classes fine, which is good, but it still has trouble with smart pointers: #include <boost/spirit/include/phoenix_bind.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/shared_ptr.hpp> #include <iostream> namespace px = boost::phoenix; using namespace px::arg_names; struct A { virtual void f() = 0; }; struct X: public A { void f() { std::cout << "X::f\n"; } }; int main() { boost::shared_ptr<A> px( new X ); px::bind( &A::f, arg1 )( px ); // fail px::bind( &A::f, *arg1 )( px ); // fail px::bind( &A::f, arg1 )( px.get() ); // fail px::bind( &A::f, arg1 )( *px ); px::bind( &A::f, px::ref( *px ) )(); px::bind( &A::f, px.get() )(); } The problem on the third line is probably caused by the rvalue-ness of px.get(). Still, boost::bind can compile it today, so Phoenix should, too. :-) Incidentally, if I #include both boost/bind.hpp and phoenix under VC7.1, I get errors in composite.hpp due to its use of _1 as an argument name. I understand that this is caused by bind.hpp and that it's probably a compiler issue, but a simple rename might fix it.

Peter Dimov wrote:
Joel de Guzman: ...
I can definitely make sure that all those are supported. I supported the lambda tests in phoenix.
Unfortunately, the Lambda tests are incomplete, as they do not cover its most frequently encountered problems. Phoenix does seem to handle abstract classes fine, which is good, but it still has trouble with smart pointers:
[snip code] Indeed.
The problem on the third line is probably caused by the rvalue-ness of px.get(). Still, boost::bind can compile it today, so Phoenix should, too. :-)
Agreed.
Incidentally, if I #include both boost/bind.hpp and phoenix under VC7.1, I get errors in composite.hpp due to its use of _1 as an argument name. I understand that this is caused by bind.hpp and that it's probably a compiler issue, but a simple rename might fix it.
I'll make sure all these issues are ironed out. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
participants (8)
-
Corrado Zoccolo
-
David Abrahams
-
Eric Niebler
-
Francois Barel
-
Giovanni Piero Deretta
-
Joel de Guzman
-
Peter Dimov
-
Steven Watanabe