Boost logo

Boost :

From: shunsuke (pstade.mb_at_[hidden])
Date: 2008-04-10 20:50:00

Giovanni Piero Deretta wrote:
> Just two things:
> - using result_of requires the 'round lambda syntax' which means
> that I can't easily use them in mpl expressions (I can't put
> mpl::placeholders in place of argument types). Of course I can round
> trip via boost.FunctionTypes but is very verbose (and probably
> slower).
> - having to specify ::type requires prefixing the expression with
> typename in templates if the type is dependent.
> It is not necessarily egg job to fix this, but it would be nice to
> have this. It is ok if I have to specify static_ in addition.

Ok. That return_of will be a candidate for it.

>> I prefer prefix, because result_of expression and function-call expression are in sync:
>> result_of<T_plus(int, int)>::type r =
>> plus(1, 2);
>> I thought 'typeof_' was too long.
>> Anyway we should decide by majority vote.
> +1 for separate namespace. If that is controversial, +1 for typeof_ instead.

After all, I will follow Boost.Fusion (and other Boost libraries).
Ditto `X_` prefix.

>> I want to define PipableFunctionObject without dependency on Egg library.
> I appreciate this need, but IMHO it is not worth it. The pipable
> support library could be a single, self contained header.

I want to make this concept independent as "curried function" is.
Also, in simple cases (e.g. arity is small, or perfect-forwarding is unneeded.),
you can make PipableFunctionObject without Egg
so that compile-time and runtime complexity can be removed.

> ADL kicks in even for template argument types (i.e. namespace of
> template arguments are considered associated namespaces), so this
> works :
> namespace egg {
> namespace pipable_support {
> struct pipable {};
> template<typename T, typename T2>
> void operator |(T, T2);
> };
> using pipable_support::pipable;
> }
> template<typename T = egg::pipable> struct my_fun_t {};
> int main() {
> my_fun_t<> my_fun = {}; // statically initialized!
> 1|my_fun;
> }
> No need for inheritance. There might also be other tricks.

It seems what Egg does.
Instead of a tag type(pipable), Egg uses a metafunction result_of.

>> Though I'm not sure what you mention,
>> curry/bind is not can-do-everything.
>> It must capture arguments by-copy.
> use ref/cref if you want capture by reference. In almost all my use
> cases, it is fine to capture the object by copy (usually a function
> object).

Egg developement started to remove ref/bll::make_const from pipable functions.
That's the forwarding problem!

> BTW, on a completely unrelated topic: it would be nice if bind/lambda
> allowed to specify the default capture behaviour, like C++0x lambdas
> (I think that with proto this wouldn't be hard to do).

I tend to think the way using ref is not so bad. :-)
`_1 < ref(m) && _2 < m` will be cumbersome in C++0x.

> I was imprecise:
> foo(bar(_,_))
> Actually corresponds to:
> lazy(foo)(protect(lazy(bar)(_1, _2))) (); // we are calling it!
> The point is that unlike lambda expressions, '_' does not cause the
> full expression to be a lazy expression (up to the protect)
> I'll try to be more clear later.

I perhaps understand what you mention.
You are trying to express *un*lambdification by using `_`.
Am I right?

I tend to think it should be expressed by using nesting-levels.
E.g. `foo(bar(_,_))` can be translated into
`nest1(foo)(nest2(bar)(_1_(_1), _1_(_2)))` // \() -> foo(\(x,y)->bar(x,y))
(or a better syntax sugar.)

> I think so, expect that I'm not sure if the result of compose is still
> a lambda expression. Of course, using a plain _1 here is pointless,
> but with more complex expressions it make more sense:
> map(range, lazy(multiply)(_1, 5) | is_less(_, 100));
> If you were to use _1 instead of _ you would need to use protect:
> map(range, lazy(multiply)(_1, 5) | protect(lazy(is_less)(_, 100)));
>> I'm still lost.
>> Why not `lazy_ex(is_less_non_curriable)(_, 10)(7)` ?
>> (Assume `lazy_ex` supports "non-numbered placeholder".)
> Almost the same, except that you would need to wrap the call to
> lazy_ex around protect(). If lazy_ex were to apply protect implicitly
> would be exaclty the same. BTW, I do not consider non-numbered
> placeholders necessary, I was just mimicking FC++ syntax.
> The protect is important, you do not need the full power of lambda
> (ie.e function composition) , so you want to stop 'lambdification'
> immediately. This is why a better name would be a lazy_simple :)

I think only the outmost lazy function knows when *un*lambdification should be performed.
BTW, bll::unlambda should be used instead of protect?

>> But, strictly speaking, it seems impossible to detect whether
>> a FunctionObject is ResultOf conforming or Lambda conforming.
>> We need C++0x Concept. (has_sig_template or has_result_template is not enough.)
> Uh? Why? doens't your result_of work seamlessy with both the sig and
> result_of protocol? where is the problem?

After some thoughts,
   "If has_sig_template is true, use Lambda protocol.
    Otherwise, use ResultOf protocol."
may be a good solution.
(But I'm not sure it is a better way to apply a heavy patch into a stable library.)
If Daniel has really succeeded to implement it, I will follow it.

BTW, bll/result_of.hpp just provides result_of specializations for Lambda functors.
That is ok.

> Never tried it, but I'm quite sure that the phoenix lambda syntax also
> let you return lambdas:
> auto always = lambda[ lambda(_a = _1)[ _1 ] ];
> auto always_10 = always(10);
> assert(alsways_10() == 10);
> should work (modulo modifying phoenix to work with rvalues).
> Disclaimer: I haven't tryed it! But even if it doesn't work with
> phoenix, it shouldn't be terribly hard to make this syntax work.

I expect Proto-professionals will invent cool syntax for nestN. :-)
Probably nestN should sleep until the day will come.
FWIW, nestN can be used with result_of,
because its expression contains only function-calls.


Shunsuke Sogame

Boost list run by bdawes at, gregod at, cpdaniel at, john at