Boost logo

Proto :

Subject: Re: [proto] : Proto transform with state
From: Eric Niebler (eric_at_[hidden])
Date: 2010-11-18 15:31:22

On 11/18/2010 1:45 PM, Thomas Heller wrote:
> Eric Niebler <eric_at_...> writes:
>> On 11/18/2010 6:09 AM, Thomas Heller wrote:
>>> Here goes the renumbering example:
> <snip>
>> Unfortunately, this doesn't actually solve the reevaluation problem ...
>> it just hides it.
> Yes, exactly.
>> If "_a" gets replaced eagerly everywhere with
>> "Renumber(_, second(proto::_state))", then that transform will actually
>> get run every time. What I want is a way to evaluate the transform,
>> store the result in a temporary, and have "_a" refer to that temporary.
> Yes, I thought of doing this ... but could not find a solution. The question is,
> do we really need this behaviour? Is replacement not enough?
> Could you make up a usecase? I can not think of one ... Regarding that counting
> example ... it can be solved by this pair hack.

The Renumber example is itself a use-case. I had to hack around the lack
of this feature with the silly type_of transform:

  struct RenumberFun
    : proto::fold<
        , make_pair(fusion::vector0<>(), proto::_state)
        , make_pair(
                , first(Renumber(_, second(proto::_state)))
            , type_of<second(Renumber(_, second(proto::_state))) >

That should simply be:

  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)

See? If Renumber gets invoked once and the result "stored" in _a, then
we can just do first(_a) and then second(_a) and not incur any runtime
overhead. type_of was a hack that took advantage of the fact that the
result of second(_a) contains no interesting runtime state (it's just a
MPL int_). There will be times when that's not the case.

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

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.

Eric Niebler
BoostPro Computing

Proto list run by eric at