Boost logo

Boost :

Subject: Re: [boost] painless currying
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2011-08-24 04:28:10


On Tuesday, August 23, 2011 10:59:36 PM Eric Niebler wrote:
> On 8/23/2011 5:21 PM, Mathias Gaunard wrote:
> > On 08/23/2011 11:15 PM, Mathias Gaunard wrote:
> >> On 08/23/2011 09:38 PM, Eric Niebler wrote:
> >>> After playing around with functional languages, I've come to envy
> >>> how
> >>> easy they make it to curry functions. Call a 2-argument function
> >>> with 1
> >>> argument and you get a function that takes 1 argument. Pass another
> >>> argument and it evaluates the function. Simple. In contrast, C++
> >>> users
> >>> have to use binders, which are not as nice.
> >>>
> >>> On a lark, I implemented a wrapper that turns any TR1-style function
> >>> object into a "curryable" function object (attached). Successive
> >>> function call invocations bind arguments until enough arguments are
> >>> bound to invoke the wrapped function. With it you can do the
> >>> following:
> >>>
> >>> curryable<std::plus<int> > p;
> >>> auto curried = p(1);
> >>> int i = curried(2);
> >>> assert(i == 3);
> >>>
> >>> Is there any interest in such a thing?
> >>
> >> It could be argued that Phoenix actors should be doing this.
> >>
> >> I also asked a lot of time ago for an easy function to turn a pfo into
> >> a
> >> phoenix actor, which I think would make phoenix much more ubiquitous.
> >>
> >> assuming that function was called lazy, and Phoenix did currying
> >> automatically, you could do
> >>
> >> int i = (lazy(std::plus<int>)(1) + 4)(3)
> >
> > Sorry, this should have been
> > int i = (lazy(std::plus<int>())(1) + 4)(3)
> > of course.

I would rather extend and reuse bind for that.

> Could you explain this? I'm guessing that lazy(std::plus<int>()) creates
> a binary function, and that lazy(std::plus<int>())(1) binds the first
> argument and returns a unary function. But what does it mean to add an
> integer to a unary function? That doesn't make sense to me.
>
> > And I remember why Phoenix doesn't do currying: that's because that only
> > works with monomorphic function objects.
>
> What only works with monomorphic functions?
>
> > Detecting and propagating monomorphism could be nice though. It could
> > eventually provide better error messages, faster compilation times, and
> > automatic currying on monomorphic function objects.
>
> What do monomorphic functions have to do with this? My currying code
> works with polymorphic functions.

I also fail to see why currying should only work on monomorphic objects.

However, the problem comes with function objects having operator() overloads
with different arity. Another problem I couldn't solve yet is how to decide
which overload gets curryied or not.
Consider:

struct foo
{
   void operator()(int);
   void operator()(int, int);
};

curryable<foo> f;
auto curried = f(1); // To curry or not to curry, that is the question

TBH, i haven studied your code yet, Eric. would be cool if solvd these
problems.
Additionally I second the call to integrte it into phoenix. Using bind and
placeholders is just not elegant enough.
There even is a feature request about it in trac:
https://svn.boost.org/trac/boost/ticket/5541

> Sorry if I'm being dense. It's pretty late over here.

And here it is too early ... will report back after studying the code.
All in all i think such a thing would be very useful!


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