Boost logo

Proto :

Subject: [proto] My own lambda for MSM / wish list
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2011-03-13 17:07:30


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.

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;

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

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

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.

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?

Christophe


Proto list run by eric at boostpro.com