|
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:
>>> http://codepad.org/K0TZamPb
> <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(
push_back(
first(proto::_state)
, 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
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.
-- Eric Niebler BoostPro Computing http://www.boostpro.com
Proto list run by eric at boostpro.com