
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