[Boost.Lambda] Some new features are suggested: return, iterating yield, & local var

Hi boosters, I'm intrested in Lambda, so I have worked out some new features, and suggest boost lib add them. What can I do next? NEW features: 1. return. why lambda lib do not include this? 2. generate iterator/iteration by lambda using yield return/yield break. 3. local/global var declare and using. 1. return e.g. boost::function<char(int)> f = ( if_ ( _1 >= 0 ) [ return_('a') ], return_('b') ); p.s. return should be supported. 2. iterator/iteration generation by lambda using yield return/yield break const char* p; // we shuld use the local var inside lambda instead of this var p. refer to section 3 iteration<char> it = ( for_(var(p) = _1, *var(p), var(p)++) [ if_(*var(p) != ' ') [ yield_return(*var(p)) ] if_(*var(p) == ';') [ yield_break() ] ] ) ("I love this game; no use"); p.s. The packing iteration interface is very like the yield keyword in C# IEnumeable 3.local/global var declare and using e.g. char a; var_name x, y, z; global_var<int>(y); // put this line inside lambda is ok, just before use it ( ( local_var<int>(x), // local var declare // global_var<int>(y), var(a) = 'a', var<int>(x) = _2, // using local var x ), ( local_var<char>(z), var(a), var<int>(x) = _1, // error! x is not local var here. var<int>(y), // ok for global even if another lambda var<char>(z) = 'b', ) ) p.s. Now, in my work. It's hard to simplify var<T>(x) to var(x). It's a hard template working.

on Tue Jan 03 2012, Huang Huan <mr.huanghuan-AT-gmail.com> wrote:
Hi boosters, I'm intrested in Lambda, so I have worked out some new features, and suggest boost lib add them. What can I do next?
Use Boost.Phoenix instead ;-) http://boost.org/libs/phoenix. It's the replacement for Boost.Lambda. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 01/03/2012 01:05 PM, Huang Huan wrote:
1. return e.g. boost::function<char(int)> f = ( if_ ( _1>= 0 ) [ return_('a') ], return_('b') ); p.s. return should be supported.
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
2. iterator/iteration generation by lambda using yield return/yield break const char* p; // we shuld use the local var inside lambda instead of this var p. refer to section 3 iteration<char> it = ( for_(var(p) = _1, *var(p), var(p)++) [ if_(*var(p) != ' ') [ yield_return(*var(p)) ] if_(*var(p) == ';') [ yield_break() ] ] ) ("I love this game; no use"); p.s. The packing iteration interface is very like the yield keyword in C# IEnumeable
yielding requires something like coroutines, with Boost.Context for example.
3.local/global var declare and using e.g. char a; var_name x, y, z; global_var<int>(y); // put this line inside lambda is ok, just before use it ( ( local_var<int>(x), // local var declare // global_var<int>(y), var(a) = 'a', var<int>(x) = _2, // using local var x ), ( local_var<char>(z), var(a), var<int>(x) = _1, // error! x is not local var here. var<int>(y), // ok for global even if another lambda var<char>(z) = 'b', ) ) p.s. Now, in my work. It's hard to simplify var<T>(x) to var(x). It's a hard template working.
Boost.Phoenix provides local variables using let/in syntax.

Yes, Boost.Phoenix do a lot forward in unname function. Unfortunately the presented features are not found in it. 2012/1/4 Mathias Gaunard <mathias.gaunard@ens-lyon.org>
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding & local var are also involved in the return architect.
Boost.Phoenix provides local variables using let/in syntax.
let(_a = 1)[...] I think the let syntx is a worse way, and you may make some mistak of my way. The let syntx is quite different from the C++ style, and _a ... _z are limited. I have implement the major part of my way, and some syntax have changed as below: // this macro is define in the lib define, use local_var_name<int id> #define var_name(x) local_var_name<__LINE__> x; // example begin here struct A { A() {}; A(char ch) {}; }; var_name(x); // just predefine the name in no type for lambda using. var_name(y); // one single line for one var_name, the macro could be redefined add some unuse code for unique line protect. var_name(z); ( ( // declaring use local_var, scope begin here local_var<A> (x) , // default construct A::A() local_var<A> (y) ('a') , // construct<A>('a') A::A(char) local_var<A> (z) (x) , // copy construct A::A(A const&) x = y // assignment A::operator=(A const&) ), ( x,y,z, // error, out of scope ) ) p.s. 1. the phoenix omitted the different way of construct/copy/assignment. 2. free style identifier name, better for code reader. Actually I have rewrote lambda, it support return/yielding, most operators, part of local var, without bind. I want to join the dev of Boost.Phoenix, if can how?

Hi Huang, On 01/04/2012 05:05 AM, Huang Huan wrote:
Yes, Boost.Phoenix do a lot forward in unname function. Unfortunately the presented features are not found in it.
2012/1/4 Mathias Gaunard<mathias.gaunard@ens-lyon.org>
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding& local var are also involved in the return architect.
I agree, "return" is very useful when you want to stay as close to C++ as possible. However, returning a value is highly unusual in functional programming and if there is something like returning something it is implemented as a Monad. Additionally i found it overly complex to implement a return statement. It would require deep introspection of the expression at hand to check if there is a return statement inside the expression to calculate the return type. Additionally, it is rather hard to deal with diverging return types (though a variant could be used here) or to output meaningful error messages (something which i would like to focus on in the next releases). Please note that I am not saying it is impossible to do that with phoenix, quite the contrary.
Boost.Phoenix provides local variables using let/in syntax.
let(_a = 1)[...] I think the let syntx is a worse way, and you may make some mistak of my way. The let syntx is quite different from the C++ style, and _a ... _z are limited.
The let syntax was chosen to mimic the style of traditional functional programming languages. Which is in contrast to the initial advertisement of phoenix stating it is "C++ in C++". In fact, the scope module is probably the place where Phoenix differs the most from traditional C++ syntax. Mainly due to the fact that things like this weren't really possible in C++ when Phoenix was invented. Joel might have some more insight on his motivation to chose that syntax! _a to _z are just some predefined local variable names. You can define your own names, with your own tags.
I have implement the major part of my way, and some syntax have changed as below:
// this macro is define in the lib define, use local_var_name<int id> #define var_name(x) local_var_name<__LINE__> x; // example begin here struct A { A() {}; A(char ch) {}; };
var_name(x); // just predefine the name in no type for lambda using. var_name(y); // one single line for one var_name, the macro could be redefined add some unuse code for unique line protect. var_name(z); ( ( // declaring use local_var, scope begin here local_var<A> (x) , // default construct A::A() local_var<A> (y) ('a') , // construct<A>('a') A::A(char) local_var<A> (z) (x) , // copy construct A::A(A const&) x = y // assignment A::operator=(A const&) ), ( x,y,z, // error, out of scope ) ) p.s. 1. the phoenix omitted the different way of construct/copy/assignment. 2. free style identifier name, better for code reader.
Your described syntax isn't that different from Pheonix. Phoenix supports the copy constructor and assignment operator. Additionally, Phoenix provides construct<A> which can be used to create instances of objects. However, I agree, that having a "free style identifier" name would greatly improve Phoenix.
Actually I have rewrote lambda, it support return/yielding, most operators, part of local var, without bind. I want to join the dev of Boost.Phoenix, if can how?
I am one of the authors, Joel de Guzman is the main author and inventor of Phoenix. Patches and ideas are always welcome! Best Regards, Thomas

On 1/4/2012 11:00 PM, Thomas Heller wrote:
let(_a = 1)[...] I think the let syntx is a worse way, and you may make some mistak of my way. The let syntx is quite different from the C++ style, and _a ... _z are limited.
The let syntax was chosen to mimic the style of traditional functional programming languages. Which is in contrast to the initial advertisement of phoenix stating it is "C++ in C++". In fact, the scope module is probably the place where Phoenix differs the most from traditional C++ syntax. Mainly due to the fact that things like this weren't really possible in C++ when Phoenix was invented. Joel might have some more insight on his motivation to chose that syntax!
It was designed with uniformity with the lambda syntax. let is more FP than procedural and closely resemble the lambda syntax. It is certainly possible to have an alternate local variable syntax similar to what you propose since a local scope does not introduce a new scope like lambda does.
However, I agree, that having a "free style identifier" name would greatly improve Phoenix.
Sure!
I am one of the authors, Joel de Guzman is the main author and inventor of Phoenix. Patches and ideas are always welcome!
Definitely! Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com

On 01/04/2012 05:05 AM, Huang Huan wrote:
Yes, Boost.Phoenix do a lot forward in unname function. Unfortunately the presented features are not found in it.
2012/1/4 Mathias Gaunard<mathias.gaunard@ens-lyon.org>
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
Sorry, I meant "since each expression is building its own function" here.
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding& local var are also involved in the return architect.
Does it call destructors correctly?

on Thu Jan 05 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 01/04/2012 05:05 AM, Huang Huan wrote:
Yes, Boost.Phoenix do a lot forward in unname function. Unfortunately the presented features are not found in it.
2012/1/4 Mathias Gaunard<mathias.gaunard@ens-lyon.org>
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
Sorry, I meant "since each expression is building its own function" here.
In principle that shouldn't limit anything, right? There's no reason that "a, b" (or any other lambda expression containing a and b) has to be evaluated via straightforward evaluations of a and b... I think. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 01/05/2012 07:18 PM, Dave Abrahams wrote:
on Thu Jan 05 2012, Mathias Gaunard<mathias.gaunard-AT-ens-lyon.org> wrote:
On 01/04/2012 05:05 AM, Huang Huan wrote:
Yes, Boost.Phoenix do a lot forward in unname function. Unfortunately the presented features are not found in it.
2012/1/4 Mathias Gaunard<mathias.gaunard@ens-lyon.org>
return is hard to implement, since each expression is building its own expression, so you need to forward it along the whole chain. Exceptions could also be used, but it's not very nice.
Sorry, I meant "since each expression is building its own function" here.
In principle that shouldn't limit anything, right? There's no reason that "a, b" (or any other lambda expression containing a and b) has to be evaluated via straightforward evaluations of a and b... I think.
It can be done, but it would require a bit of work since it would affect the whole evaluation system.

2012/1/6 Mathias Gaunard <mathias.gaunard@ens-lyon.org>:
It can be done, but it would require a bit of work since it would affect the whole evaluation system.
I agree with that. "affect the whole evaluation system." I'm willing to do this but it's seem to be a lot work for me, not as a bit work for you Mathias. I wish I can add my name the some name list on the boost site.

2012/1/6 Mathias Gaunard <mathias.gaunard@ens-lyon.org>
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding& local var are also involved in the return architect.
Does it call destructors correctly?
Yes, the stack is simulated by one object pass through the all lambda item with internal function, because all lambda item should not runtime item. It's not a real function stack, just { } domain for scope and local destruct. so yielding will be no change of the stack vars, if the stack object keeped by the iteration. I'm sorry. I have to work for my own job, so I have not so much time for woking these.

On 1/6/2012 10:15 AM, Huang Huan wrote:
2012/1/6 Mathias Gaunard <mathias.gaunard@ens-lyon.org>
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding& local var are also involved in the return architect.
Does it call destructors correctly?
Yes, the stack is simulated by one object pass through the all lambda item with internal function, because all lambda item should not runtime item. It's not a real function stack, just { } domain for scope and local destruct. so yielding will be no change of the stack vars, if the stack object keeped by the iteration.
I suspect that strategy will be slow at runtime. Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com

Yes, it's will spend some more time in push/pop the local var into/out the virtual stack(not as real stack efficiency). If only implement the return feature, using virtual stack is a bad way. But I think it's the only way to the real yielding. None of local vars will be destructed after once yielding, Hold the stack object for next yielding call. How can I get this without virtual stack? 2012/1/6 Joel de Guzman <joel@boost-consulting.com>:
On 1/6/2012 10:15 AM, Huang Huan wrote:
2012/1/6 Mathias Gaunard <mathias.gaunard@ens-lyon.org>
return is the most usefull part of function. I'm working on the implement, it's approved work with no exception for return. The architect is defferent from the lambda, I think the phoenix is also . The final functional call is wrapped, and create a heap/stack like workspace. It will support restore for yielding calls. and yielding& local var are also involved in the return architect.
Does it call destructors correctly?
Yes, the stack is simulated by one object pass through the all lambda item with internal function, because all lambda item should not runtime item. It's not a real function stack, just { } domain for scope and local destruct. so yielding will be no change of the stack vars, if the stack object keeped by the iteration.
I suspect that strategy will be slow at runtime.
Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 01/06/2012 11:25 AM, Huang Huan wrote:
None of local vars will be destructed after once yielding, Hold the stack object for next yielding call. How can I get this without virtual stack?
Use special instructions or OS-provided functions to save the context and switch to another context.

I'm sorry I omitted your first mail suggestion of Boost.Context. Context is a really good way for yielding. It will be a stargate to another world. Safety is the most important, and It's can be designed for a normal function, not only for the Phoenix. 2012/1/6 Mathias Gaunard <mathias.gaunard@ens-lyon.org>:
On 01/06/2012 11:25 AM, Huang Huan wrote:
None of local vars will be destructed after once yielding, Hold the stack object for next yielding call. How can I get this without virtual stack?
Use special instructions or OS-provided functions to save the context and switch to another context.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (5)
-
Dave Abrahams
-
Huang Huan
-
Joel de Guzman
-
Mathias Gaunard
-
Thomas Heller