Boost logo

Boost :

Subject: Re: [boost] Template metaprogramming libraries
From: David Sankel (camior_at_[hidden])
Date: 2011-09-19 10:23:17


On Fri, Sep 16, 2011 at 11:37 PM, Joel de Guzman
<joel_at_[hidden]>wrote:

> On 9/17/2011 2:07 AM, Giovanni Piero Deretta wrote:
> > On Fri, Sep 16, 2011 at 6:09 PM, David Sankel <camior_at_[hidden]> wrote:
> >> [...]
> >> The reason I said that phoenix "somewhat" gets around the bind heritage
> >> problems, which was obscure I admit, was because phoenix's use of
> >> traditional bind syntax still leaves a semantic hole.
> >>
> >> If someone writes the following:
> >>
> >> template< typename F >
> >> auto doSomething( F f ) -> decltype(...)
> >> {
> >> return bind( f, 15, _1)
> >> }
> >>
> >> And then I call doSomething elsewhere like this,
> >>
> >> doSomething( bind( g, 12, _1, _2 ) )
> >>
> >> , then the result is something most likely unexpected for the user who
> knows
> >> what doSomething means (it returns a version of f that has 15 filled in
> as
> >> its first argument (λx. λy. x(15,y))), but hasn't read its
> implementation.
> >
> > Boost.Lambda has unlambda, which is documented to prevent exactly this
> problem:
> >
> >
> http://www.boost.org/doc/libs/1_47_0/doc/html/lambda/le_in_details.html#lambda.unlambda
> >
> > With a quick search I couldn't find the phoenix equivalent of
> > unlambda, but I'm sure there must be.
>
> Phoenix does not need it because it has explicit 'lambda'
> (pun unintentional) which is required for passing in
> higher-order functions (e.g. to phoenix::for_each).
> IMO, unlambda is a hack around BLL limitations.
>
> This should be the answer David Sankel's concern too (above).
> I think there's lack of understanding of Phoenix here.
>

I think you hit the nail on the head with regards to at least my own lack of
understanding of Phoenix. Sorry to muddy the waters. I'm excited about
getting a better understanding.

It looks as if boost.lambda requires the writer of a higher order function
to guard its arguments, using unlambda. boost.phoenix, on the other hand,
requires the callers of higher order functions to guard its arguments using
lambda. Is this correct?

For comparison, the boost.lambda example,

for_each(a.begin(), a.end(), std::cout << _1 << ' ');

Would be the following in boost.phoenix?

// assuming _1 is never a function type
for_each(a.begin(), a.end(), lambda[ std::cout << _1 << ' ' ]);

I didn't catch "explicit lambda required for higher order function calls"
from reading the documentation. I wonder how it could fit in the
introduction without overly confusing the reader. It seems like a critical
thing to know IMO.

At any rate, for the record: I am for supporting De Brujin style
> in Phoenix. The infrastructure is in place. I see no reason why
> we can't support both.
>

That would be great and would be enough to entice me to use phoenix as I
love the simplicity of the De Bruijn sytax.

Maybe something like following would get a dbb implementation on top of
phoenix (extended with DeBruijn indices)

namespace dbb
{
auto _1_1 = boost::phoenix::_1_1;
//...

auto app = boost::phoenix::bind;

struct lam
{
  template< typename A>
  auto operator()( A a ) -> decltype( ... )
  {
    return boost::phoenix::lambda( a );
  }
};
}

David

-- 
David Sankel
Sankel Software
www.sankelsoftware.com
585 617 4748 (Office)

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