|
Proto : |
Subject: Re: [proto] My own lambda for MSM / wish list
From: Eric Niebler (eric_at_[hidden])
Date: 2011-03-13 23:49:23
Hi Christophe,
First let me say that I have limited bandwidth at the moment, and
apologize in advance for my short reply...
On 3/14/2011 4:07 AM, Christophe Henry wrote:
> Hi all,
>
> I started a rewrite of a major part of my eUML front-end to fix the
> issues I left open in the current version, and I'm now at the point
> where I've done enough to present what I have and get some opinions on
> the choice I'm facing: continue or switch to phoenix. I remember
> discussing the subject at the last BoostCon and it looked like my
> whishes were not possible, but it was almost one year ago, so I might
> not be up-to-date.
>
> I admit I'm having a lot of fun implementing this stuff. It's great to
> play with proto :)
>
> I wanted to start a discussion on this list to get some feedback (and
> fresh ideas) from much more knowledgeable proto experts, so here are
> some thoughts.
>
> Phoenix is a great library, but I did not find all I was looking for,
> so here is what I'm still missing. I provide an implementation to
> illustrate my wishes.
>
> 1. Creation of a default-constructible functor for MSM
>
> This one is my N°1 requirement. I started this stuff for MSM.
> MSM is based on transition tables, each transition being something like:
>
> Row < source_state , event , target_state, action , guard >
>
> With action and guard being a functor, say:
> struct guard{
> template <class Fsm,class Evt,class SourceState,class TargetState>
> bool operator()(Evt const&, Fsm&, SourceState&,TargetState& )
> {
> ...
> }
> };
>
> Which MSM then calls, for example: return guard()(evt,fsm,src,tgt);
> Note that I need a default-constructible functor whose type can be
> saved as a template argument.
>
> MSM also offers a "FP" collection of classes to build functors on the
> fly. For example, if I want a more complicated guard, I can write:
> And_< Or_<g1,g2>, Not_<g3> >
>
> eUML builds on top of this so that I can write: (g1 || g2) && !g3 .
> To achieve this, I use a typeof call of a proto expression for all
> these operators. So it's kind of a compile-time proto grammar,
> generating the above "Row".
> This is already implemented (not very well) in eUML, so I know it
> works but needs improvements.
And what you need is for the type of the Proto expression generated by
"(g1 || g2) && !g3" to be default-constructable? Have you tried doing
this with an expression adaptor and a domain in which child nodes are
all held by value (because reference members cannot be
default-constructed)? What errors did you run into?
> 2. STL, type definition
>
> Ideally, as I'm at it, I want to avoid writing functors for use in the
> STL, which is phoenix stuff. But reading the doc I didn't manage to
> find out if I can write something close to:
> std::set<int, ( _1 < _2) > s;
I don't see how that could ever work. Any way you slice it, (_1 < _2) is
an expression, not a type. decltype(_1 < _2) could be made to work, for
some suitably defined _1, _2, and <. And yes, (_1 < _2) would need to be
default-constructable.
> The re-implementation I'm working on is coming close enough for my taste:
> std::set<int, BOOST_MSM_LPP_LAMBDA_EXPR(_1 < _2) > s2;
Yeah.
> 3. STL, algorithms
>
> I found in phoenix's doc many examples with for_each but not many with
> others like transform, which require something to be returned from a
> lambda expression.
> I want:
> std::transform(vec.begin(),vec.end(),vec.begin(), ++_1 + foo_(_1) );
>
> Ideally, I'd also be able to write:
>
> std::transform(vec.begin(),vec.end(),vec.begin(),
> if_(_1)[ ++_1,return_(++_1)].else_ [return_(++_1)] );
This just looks like Phoenix. Why can't you use it directly?
> Ok, I didn't succeed yet, but I manage:
>
> std::transform(vec.begin(),vec.end(),vec.begin(),
> lambda[ if_(_1)[ ++_1, /* return */++_1 ] /*else */ [ ++_1 ] ] );
>
> Where there is a kind of implicit return and where ";" is replaced by "," :
> ++_1; return_ (++_1) => ++_1 , ++_1 /* second ++_1 is returned */
>
>
> 4. A taste of C++0x lambda: capturing
>
> One thing which is bugging me with phoenix is the ref / cref adding
> noise to my nice FP (I'm kind of a new convert). I prefer the C++0x
> solution of "capturing", which looks to me like an extended function
> declaration. For example:
> [x, y](int n) { ...}
> Or:
> [&x, &y](int n) { ... }
>
> I don't despair to achieve a similar syntax, but for the moment I have only:
> lambda[ /* capture */_capture << q <<... ] [ _1 + _c1 /* first "captured" */ ]
> Or:
> lambda[_capture << ref(q) ] [ _c1++ /* first "captured" */ ]
> Or:
> lambda[_capture << cref(q) ] [ _1 + _c1 /* first "captured" */ ]
>
> I think a better syntax would be lambda[_c1=q, _c2=4][...]
Ah, yeah. There was discussion during the early design phases about
capturing. It can't be done without (a) a "lambda" introducer like you
have, and (b) by-ref terminal capture by default by the DSEL. Phoenix
zigged, and you seem to be wishing we'd zagged. There's no going back
now. Phoenix captures terminals by value.
> 5. More compile-time DSLs, more!
>
> So, am I finally done with adding requirements? Not yet ;-)
> I have at least 2 more:
>
> - MPL. Great great library, but the template syntax is keeping too
> many away from it.
> I want what the FTMPL guys are doing (hi Matt, hi Zach).
> I'd really prefer to write _1 + _2 instead of plus<_1,_2>
You're talking about a complete C++0x redesign of MPL. Doable, but a big
job.
> - proto. Yes, proto itself. Eric talked about it in his BoostCon10
> talk. Why not write
> when_() || when_()
> instead of proto::or< proto::when<>, proto::when<> >
> Now this is really perverse. A proto grammar to generate... proto. I love it!
I love it, too! Are you volunteering? ;-) A whole-hog redesign of proto
for C++0x, taking full advantage of decltype to allow syntax like that,
is one of those things I wish I had time for.
> Ok, these ones I didn't implement them, but I can dream.
>
> The current state can be found in a MSM branch
> (http://svn.boost.org/svn/boost/branches/msm/v2_30/), with only one
> example:
> http://svn.boost.org/svn/boost/branches/msm/v2_30/libs/msm/example/lambda.cpp
>
> Disclaimer: This is NOT a finished library, merely a toy project for
> long winter evenings and there are a zillion things which need to be
> implemented (a simple stuff like _1 + 1 is not there yet, you'll need
> capturing)
>
> I want to apologize for bringing this wish list so late (after
> phoenix's review), my personal situation did not allow me to be ready
> earlier :(
>
> Thoughts?
Exciting stuff! Truly Christophe, your ideas re decltype and EDSLs in
C++ are revolutionary. But unfortunately, I fear it will require a
revolution. This is all do-able, but the changes to MPL, Proto and even
to Phoenix in the case of the lambda capture stuff would require
breaking API changes.
As for Phoenix, it might be possible to rig things so that Phoenix
primitives were wrapped or extended in such a way that they were in a
different domain that captures terminals by reference. But I'm not sure.
As for MPL and Proto, someone needs to sit down and do some hard
thinking about what meta-programming will look like in C++0x. I suspect
it'll look less like today's MPL and Proto, and much more like what you
envision. It's a huge opportunity for someone to do some really
ground-breaking work.
-- Eric Niebler BoostPro Computing http://www.boostpro.com
Proto list run by eric at boostpro.com