Boost logo

Boost :

Subject: Re: [boost] phoenix::bind
From: Joel de Guzman (joel_at_[hidden])
Date: 2008-10-02 07:10:40


Giovanni Piero Deretta wrote:

>> No, that is not the "unlambda" semantics. There needs to be 2 function
>> application there: 1) the one that substitutes the stl container for _1
>> (the leftmost _1) and 2) the one that substitutes the container's
>> element for _1 (the rightmost _1). The key point here is that phx.lambda
>> (and BLL protect), *returns a lambda-functor that returns a lambda-functor*.
>> unlambda OTOH simply returns a plain functor (non-actor). A plain functor
>> can only do one function application (bear in mind that this is phoenix
>> for_each (lazy), not std::for_each (eager)).
>
> Ok, follow me:
>
> let 'f' me an unary function object, one suitable as a parameter to for_each:
> Am I right that the following calls should work and apply every
> element of some range to 'f'?
>
> phx::for_each(_1, f)(some_range);

No. Not unless you bind f.

> Ok, now 'f' is unlambda(std::cout << _1 << std::endl) (assuming
> phoenix had unlambda with the same semantics of
> boost::lambda::unlambda. Isn't the previous example still supposed to
> work? From phoenix point of view, the internal lambda expression is
> masked so it is treated as any other function object.

No it won't work, unless you bind it. An arbitrary function object
is not lazy -- it is no different than an ordinary function. f must
be a lambda function, not an ordinary function (or function object).
And, in addition to that, it must be lambda function that returns
a lambda function.

> The problem is of course that this prevent binding local lambda
> variables to placeholders of the outer lambda expression: phoenix will
> not recongnize the result of lambda[] as part of the lambda expression
> but will treat it as an opaque function object, so it there is no
> extra evaluation round for binding the actual arguments of the outer
> lambda expression to the local variables. Still I'm sure you can come
> out with a protocol to do that without requiring the extra round to be
> shown to the user.

The premise is flawed. Your assumptions are wrong. This is not
the reason why there needs to be an extra evaluation round.
In fact, the "extra round" is never shown to the user! It happens
inside the phoenix function. Look:

     for_each(arg1,
         lambda(_a = arg2)
         [
             push_back(arg1, _a)
         ]
     )

Do you see an extra function application there? No.

>> Here's the crucial difference (using BLL) highlighting the difference:
>>
>> {
>> int x = 5;
>> int r = bind(_1, _2)(unlambda(_1), x);
>> BOOST_TEST(x == 5);
>> }
>>
>> {
>> int x = 5;
>> int r = bind(_1, _2)(protect(_1)(), x);
>> BOOST_TEST(x == 5);
>> }
>>
>> Notice that protect *requires* the additional function application:
>>
>> protect(_1)()
>>
>
> I understand the difference, but what buys us? What is the advantage?
> It feels a bit like an internal detail leaking...

Ask Jaakko. It's his interface. I can't speak for him.
I'm only saying that it is not the same and you can't replace
the one for the other. I'm also saying that it is the "protect"
model that Phoenix is adopting, not unlambda. Hence, the
misconception and misunderstanding.

Regards,

-- 
Joel de Guzman
http://www.boostpro.com
http://spirit.sf.net

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk