Boost logo

Proto :

Subject: Re: [proto] My own lambda for MSM / wish list
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2011-03-14 06:23:27


On Sunday, March 13, 2011 10:07:30 PM 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 >

I suggest you to look into spirit how semantic actions are dealt with, it
reminds me of exactly this:

> 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.

Phoenix actors are POD, they are default constractible. Do you have a
testcase where this is not the case?

> 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.
>
> 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;
>
> 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;

As Eric noted, decltype is the answer. I can't see why this should not be
possible within phoenix.

> 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) );

To answer your question, phoenix actors return their last statement. In your
case the result of ++_1 + foo_(_1) is returned.

> Ideally, I'd also be able to write:
>
> std::transform(vec.begin(),vec.end(),vec.begin(),
> if_(_1)[ ++_1,return_(++_1)].else_ [return_(++_1)] );

Ok, if_(...)[...] and if(...)[...].else_[...] are statements in phoenix,
meaning they return nothing (aka void).
The answer to your question is to simply use phoenix::if_else which is in
the operator module because it emulates the ?: operator.

> 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 ]
> ] );

This is another solution to your problem, yes

>
> 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][...]

As Eric already noted, Phoenix captures everything by value. There is no
special syntax needed to capture other variables in scope (if you want to
capture them by value, meaning that they will get copied into the phoenix
expression).
Your solution is similar to what is there in phoenix already: Local
variables and the let/lambda expressions. Your examples will have your exact
"better syntax":
lambda[ _a = q ] [ _1 + _a /* first"captured" */]
lambda[ _a = ref(q) ] [ _a++ /* first "captured" */ ]
lambda[ _a = cref(q) ] [ _1 + _a /* first "captured" */ ]

> 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>
>
> - 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!
>
> Ok, these ones I didn't implement them, but I can dream.

I am dreaming with you! :)

>
> 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

By looking at these examples i can not see what's there that is not provided
by Phoenix already.

> 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?

See above.

HTH,
Thomas



Proto list run by eric at boostpro.com