Boost logo

Boost :

Subject: Re: [boost] phoenix::bind
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2008-10-02 06:29:29


On Thu, Oct 2, 2008 at 4:46 AM, Joel de Guzman
<joel_at_[hidden]> wrote:
> Peter Dimov wrote:
>>
>> Joel de Guzman:
>>
>>> Maybe you want:
>>>
>>> let(_a = 0)[ ++_a ]
>>
>> Maybe I do. :-)
>>
>>> phx::for_each(_1, lambda[std::cout << _1 << std::endl])
>>>
>>> Notice that like protect, there are two function invocations happening
>>> here.
>>
>> The confusion here comes from the fact that the above would work if
>> lambda[] had "unlambda" semantics, that is, if it returned a function object
>> that was not a phoenix expression.
>
> 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);

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.

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.

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

-- 
gpd

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