Re: [proto] : Proto transform with state
On 11/18/2010 4:56 AM, Eric Niebler wrote: I think Proto transforms need a let statement for storing intermediate results. Maybe something like this: struct RenumberFun : proto::fold _ , make_pair(fusion::vector0(), proto::_state) , let _a( Renumber(_, second(proto::_state)) ) , make_pair( push_back( first(proto::_state) , first(_a) ) , second(_a) ) {}; I haven't a clue how this would be implemented. It's fun to think about this stuff, but I wish it actually payed the bills. Bills be damned. I just committed to trunk an implementation of proto::let, along with tests and reference docs. End-user docs are still todo. -- Eric Niebler BoostPro Computing http://www.boostpro.com ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
On 1/29/2011 7:49 PM, Eric Niebler wrote: Bills be damned. I just committed to trunk an implementation of proto::let, along with tests and reference docs. End-user docs are still todo. sigh As often happens, I woke up this morning knowing this code was broken, so I pulled it. I think I finally know how to fix it, though. -- Eric Niebler BoostPro Computing http://www.boostpro.com signature.asc Description: OpenPGP digital signature ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
On 12/6/2010 4:50 PM, Thomas Heller wrote: Eric Niebler wrote: I played with the let transform idea over the weekend. It *may* be possible to accomplish without the two problems I described above. See the attached let transform (needs latest Proto trunk). I'm also attaching the Renumber example, reworked to use let. snip Without having looked at it too much ... this looks a lot like the environment in phoenix. Maybe this helps in cleaning it out a bit. I tend to doubt it would help clean up the implementation of Phoenix environments. These features exist on different meta-levels: one (proto::let) is a feature for compiler-construction (Proto), the other (phoenix::let) is a language feature (Phoenix). The have roughly the same purpose within their purview, but as their purviews are separated by one great, big Meta, it's not clear that they have anything to do with each other. -- Eric Niebler BoostPro Computing http://www.boostpro.com ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
Eric Niebler wrote: On 12/6/2010 4:50 PM, Thomas Heller wrote: Eric Niebler wrote: I played with the let transform idea over the weekend. It *may* be possible to accomplish without the two problems I described above. See the attached let transform (needs latest Proto trunk). I'm also attaching the Renumber example, reworked to use let. snip Without having looked at it too much ... this looks a lot like the environment in phoenix. Maybe this helps in cleaning it out a bit. I tend to doubt it would help clean up the implementation of Phoenix environments. These features exist on different meta-levels: one (proto::let) is a feature for compiler-construction (Proto), the other (phoenix::let) is a language feature (Phoenix). The have roughly the same purpose within their purview, but as their purviews are separated by one great, big Meta, it's not clear that they have anything to do with each other. *Dough* misunderstanding here. I didn't mean to clean up the phoenix scope expressions with the help of proto::let. I was thinking, maybe proto::let can borrow something from phoenix scopes on a conceptual level. ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
Eric Niebler wrote: On 12/7/2010 3:13 PM, Thomas Heller wrote: Eric Niebler wrote: Now they do: T()(e,s,d). Inside T::impl, D had better be the type of d. Nowhere does the _data transform appear in this code, so changing _data to be smart about environments and scopes won't save you if you've monkeyed with the data parameter. Very true. Something like proto::transform_env_impl could help. Introduce a new type of primitive transform which is aware of this environment. The usual transform_impl can still be used. By calling T()(e,s,d) you just create a 2-tuple. The first parameter is the state, second data. Just thinking out loud here ... So transform_impl strips the data parameter of the let scope stuff, and the local variables like _a don't use transform_impl and see the scope with the locals? Well, it's not that simple Consider: make int(_a) If make::impl uses transform_impl, it strips the let scope before _a gets to see the local variables. If this is to work, most of Proto's transforms must be special and pass the let scope through. That means proto::call, proto::make, proto::lazy and proto::when, at least. But ... it just might work. Good thinking! time passes... No, wait a minute. Look again: struct T : transformT { templateclass E, class S, class D struct impl : transform_implE, S, D { // do something with D }; }; T::impl gets passed D *before* transform_impl has a change to fix it up. Any existing transform that actually uses D and assumes it's what they passed in is going to be totally hosed. In order to make existing transforms let-friendly, they would all need to be changed. That's no good. Bummer, I was excited for a minute there. :-/ Yes ... this would basically mean a complete rewrite ... no good. -- Proto V5, you might save the thought for the C++0x rewrite :) ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
On 11/18/2010 3:31 PM, Eric Niebler wrote: On 11/18/2010 1:45 PM, Thomas Heller wrote: Eric Niebler e...@... writes: It's REALLY hard. The let context needs to be bundled with the Expr, State, or Data parameters somehow, but in a way that's transparent. I don't actually know if it's possible. Very hard ... yeah. I am thinking that we can maybe save these variables in the transform? I'm thinking we just stuff it into the Data parameter. We have a let_scope template that is effectively a pair containing: 1. The user's original Data, and 2. A Fusion map from local variables (_a) to values. The let transform evaluates the bindings and stores the result in the let_scope's Fusion map alongside the user's Data. We pass the let_scope as the new Data parameter. _a is itself a transform that looks up the value in Data's Fusion map. The proto::_data transform is changed to be aware of let_scope and return only the original user's Data. This can work. We also need to be sure not to break the new proto::external_transform. The problems with this approach as I see it: 1. It's not completely transparent. Custom primitive transforms will see that the Data parameter has been monkeyed with. 2. Local variables like _a are not lexically scoped. They are, in fact, dynamically scoped. That is, you can access _a outside of a let clause, as long as you've been called from within a let clause. Might be worth it. But as there's no pressing need, I'm content to let this simmer. Maybe we can think of something better. I played with the let transform idea over the weekend. It *may* be possible to accomplish without the two problems I described above. See the attached let transform (needs latest Proto trunk). I'm also attaching the Renumber example, reworked to use let. This code is NOT ready for prime time. I'm not convinced it behaves sensibly in all cases. I'm only posting it as a curiosity. You're insane if you use this in production code. Etc, etc. -- Eric Niebler BoostPro Computing http://www.boostpro.com #ifndef BOOST_PP_IS_ITERATING /// /// \file let.hpp /// Contains definition of the let transform. // // Copyright 2010 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROTO_TRANSFORM_LET_HPP_EAN_12_04_2010 #define BOOST_PROTO_TRANSFORM_LET_HPP_EAN_12_04_2010 #include boost/preprocessor/cat.hpp #include boost/preprocessor/facilities/intercept.hpp #include boost/preprocessor/repetition/repeat.hpp #include boost/preprocessor/repetition/enum.hpp #include boost/preprocessor/repetition/enum_trailing.hpp #include boost/preprocessor/repetition/enum_params.hpp #include boost/preprocessor/repetition/enum_binary_params.hpp #include boost/preprocessor/repetition/enum_trailing_params.hpp #include boost/preprocessor/repetition/enum_params_with_a_default.hpp #include boost/preprocessor/repetition/enum_trailing_binary_params.hpp #include boost/preprocessor/facilities/intercept.hpp #include boost/preprocessor/iteration/iterate.hpp #include boost/mpl/if.hpp #include boost/mpl/eval_if.hpp //#include boost/mpl/print.hpp #include boost/mpl/identity.hpp #include boost/mpl/aux_/template_arity.hpp #include boost/mpl/aux_/lambda_arity_param.hpp #include boost/fusion/include/map.hpp #include boost/fusion/include/at_key.hpp #include boost/proto/proto_fwd.hpp #include boost/proto/traits.hpp #include boost/proto/transform/impl.hpp namespace boost { namespace proto { // Fwd declarations to be moved to proto_fwd.hpp template BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_PROTO_MAX_ARITY, typename Local, void) , typename Transform = void struct let; templatetypename Tag struct local; namespace detail { // A structure that holds both a map of local variables as // well as the original Data parameter passed to the let transform templatetypename LocalMap, typename Data struct let_scope { typedef LocalMap local_map_type; typedef Data data_type; let_scope(LocalMap l, Data d) : locals(l) , data(d) {} LocalMap locals; Data data; private: let_scope operator=(let_scope const ); }; templatetypename Expr, typename State, typename Data BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PROTO_MAX_ARITY, typename Local, = void BOOST_PP_INTERCEPT) , typename Transform = void struct init_local_map;
Re: [proto] : Proto transform with state
Eric Niebler wrote: On 11/18/2010 3:31 PM, Eric Niebler wrote: On 11/18/2010 1:45 PM, Thomas Heller wrote: Eric Niebler e...@... writes: It's REALLY hard. The let context needs to be bundled with the Expr, State, or Data parameters somehow, but in a way that's transparent. I don't actually know if it's possible. Very hard ... yeah. I am thinking that we can maybe save these variables in the transform? I'm thinking we just stuff it into the Data parameter. We have a let_scope template that is effectively a pair containing: 1. The user's original Data, and 2. A Fusion map from local variables (_a) to values. The let transform evaluates the bindings and stores the result in the let_scope's Fusion map alongside the user's Data. We pass the let_scope as the new Data parameter. _a is itself a transform that looks up the value in Data's Fusion map. The proto::_data transform is changed to be aware of let_scope and return only the original user's Data. This can work. We also need to be sure not to break the new proto::external_transform. The problems with this approach as I see it: 1. It's not completely transparent. Custom primitive transforms will see that the Data parameter has been monkeyed with. 2. Local variables like _a are not lexically scoped. They are, in fact, dynamically scoped. That is, you can access _a outside of a let clause, as long as you've been called from within a let clause. Might be worth it. But as there's no pressing need, I'm content to let this simmer. Maybe we can think of something better. I played with the let transform idea over the weekend. It *may* be possible to accomplish without the two problems I described above. See the attached let transform (needs latest Proto trunk). I'm also attaching the Renumber example, reworked to use let. This code is NOT ready for prime time. I'm not convinced it behaves sensibly in all cases. I'm only posting it as a curiosity. You're insane if you use this in production code. Etc, etc. Without having looked at it too much ... this looks a lot like the environment in phoenix. Maybe this helps in cleaning it out a bit. ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
Eric Niebler e...@... writes: On 11/17/2010 2:18 PM, joel falcou wrote: On 17/11/10 19:46, Eric Niebler wrote: See the attached code. I wish I had a better answer. It sure would be nice to generalize this for other times when new state needs to bubble up and back down. Just chiming in. We had the exact same problem in quaff where needed to carry on a process ID over the trasnform of parallel statement. If it can make you worry less Eric, we ended with the exact same workaround. There's another issue. Look here: // don't evaluate T at runtime, but default-construct // an object of T's result type. templatetypename T struct type_of : proto::makeproto::callT {}; struct RenumberFun : proto::fold _ , make_pair(fusion::vector0(), proto::_state) , make_pair( push_back( first(proto::_state) //--1 , first(Renumber(_, second(proto::_state))) ) //---2 , type_ofsecond(Renumber(_, second(proto::_state))) ) {}; Notice that the Renumber algorithm needs to be invoked twice with the same arguments. In this case, we can avoid the runtime overhead of the second invocation by just using the type information, but that's not always going to be the case. There doesn't seem to be a way around it, either. I think Proto transforms need a let statement for storing intermediate results. Maybe something like this: struct RenumberFun : proto::fold _ , make_pair(fusion::vector0(), proto::_state) , let _a( Renumber(_, second(proto::_state)) ) , make_pair( push_back( first(proto::_state) , first(_a) ) , type_ofsecond(_a) ) {}; I haven't a clue how this would be implemented. It's fun to think about this stuff, but I wish it actually payed the bills. Ok ... I implemented let! Here goes the renumbering example: http://codepad.org/K0TZamPb The change is in line 296 rendering RenumberFun to: struct RenumberFun : proto::fold _ , make_pair(fusion::vector(), proto::_state) , let _a(Renumber(_, second(proto::_state))) , make_pair( push_back( first(proto::_state) , first(_a) ) , type_ofsecond(_a) ) {}; The implementation of let actually was quite easy ... here is how it works: letLocals, Transform is a transform taking definitions of local variables and the transform these locals will get applied to. A local definition is in the form of: LocalName(LocalTransform) If the specified transform has LocalName embedded, it will get replaced by LocalTransform. I also implemented the definition of more than one local ... this is done by reusing proto::and_: letproto::and_LocalName0(LocalTransform0), ... LocalNameN(LocalTransformN), Transform The replacement is done from the end to the beginning, making it possible to refer in a LocalTransformN to a LocalNameN-1, this gets replaced automatically! Hope that helps! Thomas ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
On 17/11/10 19:46, Eric Niebler wrote: See the attached code. I wish I had a better answer. It sure would be nice to generalize this for other times when new state needs to bubble up and back down. Just chiming in. We had the exact same problem in quaff where needed to carry on a process ID over the trasnform of parallel statement. If it can make you worry less Eric, we ended with the exact same workaround. ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto
Re: [proto] : Proto transform with state
On 11/17/2010 2:18 PM, joel falcou wrote: On 17/11/10 19:46, Eric Niebler wrote: See the attached code. I wish I had a better answer. It sure would be nice to generalize this for other times when new state needs to bubble up and back down. Just chiming in. We had the exact same problem in quaff where needed to carry on a process ID over the trasnform of parallel statement. If it can make you worry less Eric, we ended with the exact same workaround. There's another issue. Look here: // don't evaluate T at runtime, but default-construct // an object of T's result type. templatetypename T struct type_of : proto::makeproto::callT {}; struct RenumberFun : proto::fold _ , make_pair(fusion::vector0(), proto::_state) , make_pair( push_back( first(proto::_state) //--1 , first(Renumber(_, second(proto::_state))) ) //---2 , type_ofsecond(Renumber(_, second(proto::_state))) ) {}; Notice that the Renumber algorithm needs to be invoked twice with the same arguments. In this case, we can avoid the runtime overhead of the second invocation by just using the type information, but that's not always going to be the case. There doesn't seem to be a way around it, either. I think Proto transforms need a let statement for storing intermediate results. Maybe something like this: struct RenumberFun : proto::fold _ , make_pair(fusion::vector0(), proto::_state) , let _a( Renumber(_, second(proto::_state)) ) , make_pair( push_back( first(proto::_state) , first(_a) ) , type_ofsecond(_a) ) {}; I haven't a clue how this would be implemented. It's fun to think about this stuff, but I wish it actually payed the bills. -- Eric Niebler BoostPro Computing http://www.boostpro.com ___ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto