[MPL] unlambda primitive (was [Boost-users] [MPL] map question)

Aleksey Gurtovoy wrote:
Daniel Wallin writes:
I'm sorry if I'm being thick here, but I can't grasp this. To me protect looks exactly like what is needed here. I have always thought of protect as delaying the placeholder substitution one step,
Well, again, it's not what it does. If we are to talk about introducing another primitive that would cover the OP use case, then it's another discussion (which should be taken to the developers list).
Well OK, let's do that. What are your thoughts about adding something like this? template< typename BOOST_MPL_AUX_NA_PARAM(T) > struct unlambda { template< typename X = na BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(1, typename X, na) > struct apply { typedef T type; }; typedef unlambda type; }; ... /// special case for 'unlambda' template< typename T, typename Tag > struct lambda< mpl::unlambda<T>,Tag, int_<1> > { typedef true_ is_le; typedef mpl::bind0<mpl::unlambda<T> > result_; typedef result_ type; }; -- Daniel Wallin

Daniel Wallin writes:
Well OK, let's do that. What are your thoughts about adding something like this?
template< typename BOOST_MPL_AUX_NA_PARAM(T) > struct unlambda { template< typename X = na BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(1, typename X, na) > struct apply { typedef T type; };
typedef unlambda type; };
...
/// special case for 'unlambda' template< typename T, typename Tag > struct lambda< mpl::unlambda<T>,Tag, int_<1> > { typedef true_ is_le; typedef mpl::bind0<mpl::unlambda<T> > result_; typedef result_ type; };
While straightforward, a primitive like 'unlambda' won't cover many use cases that I consider important. I'd be inclined towards more systematic approach to nested scoping, something along the lines of what is discussed in the attached conversation (long, but insightful). May be even implicit scoping for the library algorithms as described in one of these emails. Thoughts are welcome. -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
Daniel Wallin writes:
Well OK, let's do that. What are your thoughts about adding something like this?
[...]
While straightforward, a primitive like 'unlambda' won't cover many use cases that I consider important. I'd be inclined towards more systematic approach to nested scoping, something along the lines of what is discussed in the attached conversation (long, but insightful). May be even implicit scoping for the library algorithms as described in one of these emails.
Hi Aleksey, Currently, Phoenix has local variables, lambda and scopes. IMHO, Phoenix-2 has the best syntax yet that satisfies all requirements so far: http://tinyurl.com/6qyqr Here's the solution to the use-case posed in the email exchanges above: write a lambda expression that accepts: 1. a 2-dimensional container (e.g. vector<vector<int> >) 2. a container element (e.g. int) and pushes-back the element to each of the vector<int>. Solution: for_each(_1, lambda(_a = _2) [ push_back(_1, _a) ] ) Since we do not have access to the arguments of the outer scopes beyond the lambda-body, we introduce a local variable _a that captures the second outer argument: _2. Hence: _a = _2. This local variable is visible inside the lambda scope. << Daniel helped in the brainstorming too. >> Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel writes:
Hi Aleksey,
Hi Joel,
Currently, Phoenix has local variables, lambda and scopes. IMHO, Phoenix-2 has the best syntax yet that satisfies all requirements so far:
Here's the solution to the use-case posed in the email exchanges above:
write a lambda expression that accepts:
1. a 2-dimensional container (e.g. vector<vector<int> >) 2. a container element (e.g. int)
and pushes-back the element to each of the vector<int>.
Solution:
for_each(_1, lambda(_a = _2) [ push_back(_1, _a) ] )
Since we do not have access to the arguments of the outer scopes beyond the lambda-body, we introduce a local variable _a that captures the second outer argument: _2. Hence: _a = _2. This local variable is visible inside the lambda scope.
Any particular reason why you decided against implicit scoping along the lines of for_each( _1, push_back(_1, outer(_2)) ) ? -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
?
It doesn't generalize all that well, FWIW. What if you have to go out by 2 scopes? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
?
It doesn't generalize all that well, FWIW. What if you have to go out by 2 scopes?
outer(outer(_2)) or outer<2>(_2) livable, IMO, but I prefer the more general local-variable approach. The syntax is terser, FWIW. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

David Abrahams writes:
Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
?
It doesn't generalize all that well, FWIW.
Of course it does.
What if you have to go out by 2 scopes?
outer( outer(_2) ) or outer<2>(_2) All this is discussed in the conversation I posted earlier -- in which you participated ;). -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
David Abrahams writes:
Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
?
It doesn't generalize all that well, FWIW.
Of course it does.
What if you have to go out by 2 scopes?
outer( outer(_2) )
or outer<2>(_2)
All this is discussed in the conversation I posted earlier -- in which you participated ;).
Yeah, it was just hard to read for the aforementioned reason. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
?
It doesn't generalize all that well, FWIW.
Of course it does.
What if you have to go out by 2 scopes?
outer( outer(_2) )
or outer<2>(_2)
All this is discussed in the conversation I posted earlier -- in which you participated ;).
Yeah, it was just hard to read for the aforementioned reason.
I forgot to mention that the "outer" solution has another drawback: it is more expensive. We have to make a full copy of the entire arguments tuple of each scope outwards. With the local vars solution, you only use what you need. I know, I know :), yes you can also make "outer" only get what it needs by inspecting the scopes. But that involves a lot of compile time processing for little gain. Implementation wise, the local variables solution gives more bang for the buck. I'm still unsure if we need two ways to do things. That might be a reason why I hesitated to doc the "outer" stuff. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel writes:
I forgot to mention that the "outer" solution has another drawback: it is more expensive.
At run-time, that is :).
We have to make a full copy of the entire arguments tuple of each scope outwards. With the local vars solution, you only use what you need.
I know, I know :), yes you can also make "outer" only get what it needs by inspecting the scopes. But that involves a lot of compile time processing for little gain. Implementation wise, the local variables solution gives more bang for the buck.
The balance seems to be different at compile-time. 'scope' + 'outer' are almost trivial to implement and also the winners syntax-wise (IMO). -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
Joel writes:
write a lambda expression that accepts:
1. a 2-dimensional container (e.g. vector<vector<int> >) 2. a container element (e.g. int)
and pushes-back the element to each of the vector<int>.
Solution:
for_each(_1, lambda(_a = _2) [ push_back(_1, _a) ] )
Since we do not have access to the arguments of the outer scopes beyond the lambda-body, we introduce a local variable _a that captures the second outer argument: _2. Hence: _a = _2. This local variable is visible inside the lambda scope.
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
Actually, both solutions are orthogonal. I still have the code for "outer". I just don't have it documented yet. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel writes:
Aleksey Gurtovoy wrote:
Any particular reason why you decided against implicit scoping along the lines of
for_each( _1, push_back(_1, outer(_2)) )
Actually, both solutions are orthogonal. I still have the code for "outer". I just don't have it documented yet.
Oh, OK. Thanks for the update on this! -- Aleksey Gurtovoy MetaCommunications Engineering

[I've sent the reply below yesterday, but for some reason it didn't go through] Daniel Wallin writes:
Well OK, let's do that. What are your thoughts about adding something like this?
template< typename BOOST_MPL_AUX_NA_PARAM(T) > struct unlambda { template< typename X = na BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(1, typename X, na) > struct apply { typedef T type; };
typedef unlambda type; };
...
/// special case for 'unlambda' template< typename T, typename Tag > struct lambda< mpl::unlambda<T>,Tag, int_<1> > { typedef true_ is_le; typedef mpl::bind0<mpl::unlambda<T> > result_; typedef result_ type; };
While straightforward, a primitive like 'unlambda' won't cover many use cases that I consider important. I'd be inclined towards more systematic approach to nested scoping, something along the lines of what is discussed in the attached conversation (long, but insightful). May be even implicit scoping for the library algorithms as described in one of these emails. Thoughts are welcome. -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
[I've sent the reply below yesterday, but for some reason it didn't go through]
Maybe because it has an entire message digest embedded in it??! Is that intentional? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Aleksey Gurtovoy wrote:
[I've sent the reply below yesterday, but for some reason it didn't go through]
Maybe because it has an entire message digest embedded in it??!
Is that intentional?
Apologies to everyone. Aleksey's post is fine; it's just Mozilla Thunderbird's preview pane that makes it look as though something is very, very wrong there. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (5)
-
Aleksey Gurtovoy
-
Daniel Wallin
-
David Abrahams
-
Joel
-
Joel