17

EDIT: I use curry below, but have been informed this is instead partial application.

I've been trying to figure out how one would write a curry function in C++, and i actually figured it out!

#include <stdio.h>
#include <functional>

template< class Ret, class Arg1, class ...Args >
auto curry(  Ret f(Arg1,Args...), Arg1 arg )
    -> std::function< Ret(Args...) >
{
    return [=]( Args ...args ) { return f( arg, args... ); };
}

And i wrote a version for lambdas, too.

template< class Ret, class Arg1, class ...Args >
auto curry(  const std::function<Ret(Arg1,Args...)>& f, Arg1 arg )
    -> std::function< Ret(Args...) >
{
    return [=]( Args ...args ) { return f( arg, args... ); };
}

The tests:

int f( int x, int y )
{
    return x + y;
}

int main()
{
    auto f5 = curry( f, 5 );
    auto g2 = curry( std::function<int(int,int)>([](int x, int y){ return x*y; }), 2 );
    printf("%d\n",f5(3));
    printf("%d\n",g2(3));
}

Yuck! The line initializing g2 is so large that i might as well have curried it manually.

auto g2 = [](int y){ return 2*y; };

Much shorter. But since the intent is to have a really generic and convenient curry function, could i either (1) write a better function or (2) somehow my lambda to implicitly construct an std::function? I fear the current version violates the rule of least surprise when f is not a free function. Especially annoying is how no make_function or similar-type function that i know of seems to exist. Really, my ideal solution would just be a call to std::bind, but i'm not sure how to use it with variadic templates.

PS: No boost, please, but i'll settle if nothing else.

EDIT: I already know about std::bind. I wouldn't be writing this function if std::bind did exactly what i wanted with the best syntax. This should be more of a special case where it only binds the first element.

As i said, my ideal solution should use bind, but if i wanted to use that, i'd use that.

SplinterOfChaos
  • 469
  • 3
  • 12
  • You say no boost, but why? If you don't want to use the library you could still copy the functionality it provides. – N_A Jul 24 '12 at 12:14
  • Your curry function has the functionality of bind. You could alternatively use `auto fn = std::bind([](int x, int y){return x*y;}, std::placeholders::_1, 5);` – mkaes Jul 24 '12 at 12:19
  • mydogisbox: Because in the five years i've been coding, i've grown a disdain for Boost. I could re-implement some feature, if it was sufficiently small, but i don't expect small and functional from Boost. Plus, a lot of its features have become standard. I am, however, always open to being proved wrong. – SplinterOfChaos Jul 24 '12 at 12:35
  • mkaes: Of course i could! But instead, i want to use a more convenient syntax that knows it's only binding the first argument. bind is plenty generic, i want something less. – SplinterOfChaos Jul 24 '12 at 12:38
  • 2
    What you have here is not really currying, it is rather some kind of partial application (cf. the comments on [this question](http://stackoverflow.com/q/9944906/20984)). For partial application, the standard library provides `std::bind`, but you will need to use placeholders for the parameters you don't want to bind. Alternatively, you could fall back to the "old" [`std::bind1st`](http://www.sgi.com/tech/stl/binder1st.html). – Luc Touraille Jul 24 '12 at 12:39
  • I know that already. My first attempt at this function used bind and my ideal solution still does. – SplinterOfChaos Jul 24 '12 at 12:41
  • 2
    I understand that your problem is that you want to avoid having to use placeholders (you could perhaps make that clearer in your question). I found [this similar question](http://stackoverflow.com/q/8059182/20984), which unfortunately has no definitive answer yet... – Luc Touraille Jul 24 '12 at 12:45
  • I do not recommend trying to solve anything that leads or amounts to inspecting functors. You'll forget to deal with surrogate functors (for whatever evil that may cause), and you won't be able to deal with overloaded functors without severe pain/loss of all convenience (and those functors aren't rare). – Luc Danton Jul 24 '12 at 14:43
  • "*PS: No boost, please*" That's silly -- this is _exactly_ what [Boost.Phoenix](http://www.boost.org/libs/phoenix/) exists for. – ildjarn Jul 24 '12 at 18:37
  • That library is par-for-the-course on why i don't use Boost. The moment i see a lambda hidden in regular-looking code, i know it's another Boost WTF C++-unlike syntax moment. Then, there's an example if_(x)[ ... ]. I'm way to OCD to put up with that. – SplinterOfChaos Jul 24 '12 at 23:50
  • So the library that does exactly what you're asking for is why you _don't_ use Boost? Lost cause... – ildjarn Jul 25 '12 at 02:03
  • Odd, non-idiomatic syntax is exactly the opposite of what i'm asking for. Not wanting to use a given library does not make me a "lost cause". Adding Boost as a dependency to my project isn't any better than using std::bind, which comes standard, so i don't see how this does "exactly what [I'm] asking for". – SplinterOfChaos Jul 25 '12 at 03:42

4 Answers4

11

Your curry function is just a scaled down inefficient subcase of std::bind (std::bind1st and bind2nd should not be used anymore now that we have std::result_of)

Your two lines read in fact

auto f5 = std::bind(f, 5, _1);
auto g2 = std::bind(std::multiplies<int>(), 2, _1);

after having used namespace std::placeholders. This carefully avoids the boxing into std::function and allows the compiler to inline more easily the result at the call site.

For functions of two arguments, hacking something like

auto bind1st(F&& f, T&& t) 
    -> decltype(std::bind(std::forward<F>(f), std::forward<T>(t), _1))
{
    return std::bind(std::forward<F>(f), std::forward<T>(t), _1)
}

may work, but it is difficult to generalize to the variadic case (for which you'd end up rewriting a lot of the logic in std::bind).

Also currying is not partial application. Currying has "signature"

((a, b) -> c) -> (a -> b -> c)

ie. it is the action to transform a function taking two arguments into a function returning a function. It has an inverse uncurry performing the reverse operation (for mathematicians: curry and uncurry are isomorphisms, and define an adjunction). This inverse is very cumbersome to write in C++ (hint: use std::result_of).

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • 1
    I think the OP wants to avoid the need for placeholders. IIUC, he wants a `bind1st` version that works with any callable object. `bind` forces you to bind all parameters, which can be a burden when there is a lot of them, or when you are writing generic code. – Luc Touraille Jul 24 '12 at 12:49
  • 2
    I think you confused currying and uncurrying: currying transforms a n-ary function into a "chain" of unary functions, while uncurrying does the opposite. – Luc Touraille Jul 24 '12 at 12:53
  • 1
    Thanks, now i get the difference. I guess just an FYI, i actually had found some C++ code that curried a while (https://github.com/LeszekSwirski/cpp-curry), but i realized that i'd much rather have partial application. – SplinterOfChaos Jul 24 '12 at 13:03
  • 1
    No, `std::bind` is not a good partial application. `std::bind` has a bunch of baggage that gets in the way of it being a pure partial application that *will* bite you. – Yakk - Adam Nevraumont Sep 04 '15 at 00:18
9

This is a way to have currying in C++ and may or may not be relevant after the recent edits to the OP.

Due to overloading it is very problematic to inspect a functor and detect its arity. What is possible however is that given a functor f and an argument a, we can check if f(a) is a valid expression. If it isn't, we can store a and given a following argument b we can check if f(a, b) is a valid expression, and so on. To wit:

#include <utility>
#include <tuple>

/* Two SFINAE utilities */

template<typename>
struct void_ { using type = void; };

template<typename T>
using Void = typename void_<T>::type;

// std::result_of doesn't play well with SFINAE so we deliberately avoid it
// and roll our own
// For the sake of simplicity this result_of does not compute the same type
// as std::result_of (e.g. pointer to members)
template<typename Sig, typename Sfinae = void>
struct result_of {};

template<typename Functor, typename... Args>
struct result_of<
    Functor(Args...)
    , Void<decltype( std::declval<Functor>()(std::declval<Args>()...) )>
> {
    using type = decltype( std::declval<Functor>()(std::declval<Args>()...) );
};

template<typename Functor, typename... Args>
using ResultOf = typename result_of<Sig>::type;

template<typename Functor, typename... Args>
class curry_type {
    using tuple_type = std::tuple<Args...>;
public:
    curry_type(Functor functor, tuple_type args)
        : functor(std::forward<Functor>(functor))
        , args(std::move(args))
    {}

    // Same policy as the wrappers from std::bind & others:
    // the functor inherits the cv-qualifiers from the wrapper
    // you might want to improve on that and inherit ref-qualifiers, too
    template<typename Arg>
    ResultOf<Functor&(Args..., Arg)>
    operator()(Arg&& arg)
    {
        return invoke(functor, std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))));
    }

    // Implementation omitted for brevity -- same as above in any case
    template<typename Arg>
    ResultOf<Functor const&(Args..., Arg)>
    operator()(Arg&& arg) const;

    // Additional cv-qualified overloads omitted for brevity

    // Fallback: keep calm and curry on
    // the last ellipsis (...) means that this is a C-style vararg function
    // this is a trick to make this overload (and others like it) least
    // preferred when it comes to overload resolution
    // the Rest pack is here to make for better diagnostics if a user erroenously
    // attempts e.g. curry(f)(2, 3) instead of perhaps curry(f)(2)(3)
    // note that it is possible to provide the same functionality without this hack
    // (which I have no idea is actually permitted, all things considered)
    // but requires further facilities (e.g. an is_callable trait)
    template<typename Arg, typename... Rest>
    curry_type<Functor, Args..., Arg>
    operator()(Arg&& arg, Rest const&..., ...)
    {
        static_assert( sizeof...(Rest) == 0
                       , "Wrong usage: only pass up to one argument to a curried functor" );
        return { std::forward<Functor>(functor), std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))) };
    }

    // Again, additional overloads omitted

    // This is actually not part of the currying functionality
    // but is here so that curry(f)() is equivalent of f() iff
    // f has a nullary overload
    template<typename F = Functor>
    ResultOf<F&(Args...)>
    operator()()
    {
        // This check if for sanity -- if I got it right no user can trigger it
        // It *is* possible to emit a nice warning if a user attempts
        // e.g. curry(f)(4)() but requires further overloads and SFINAE --
        // left as an exercise to the reader
        static_assert( sizeof...(Args) == 0, "How did you do that?" );
        return invoke(functor, std::move(args));
    }

    // Additional cv-qualified overloads for the nullary case omitted for brevity

private:
    Functor functor;
    mutable tuple_type args;

    template<typename F, typename Tuple, int... Indices>
    ResultOf<F(typename std::tuple_element<Indices, Tuple>::type...)>
    static invoke(F&& f, Tuple&& tuple, indices<Indices...>)
    {
        using std::get;
        return std::forward<F>(f)(get<Indices>(std::forward<Tuple>(tuple))...);
    }

    template<typename F, typename Tuple>
    static auto invoke(F&& f, Tuple&& tuple)
    -> decltype( invoke(std::declval<F>(), std::declval<Tuple>(), indices_for<Tuple>()) )
    {
        return invoke(std::forward<F>(f), std::forward<Tuple>(tuple), indices_for<Tuple>());
    }
};

template<typename Functor>
curry_type<Functor> curry(Functor&& functor)
{ return { std::forward<Functor>(functor), {} }; }

The above code compiles using a snapshot of GCC 4.8 (barring copy-and-paste errors), provided that there is an indices type and an indices_for utility. This question and its answer demonstrates the need and implementation of such things, where seq plays the role of indices and gens can be used to implement a (more convenient) indices_for.

Great care is taken in the above when it comes to value category and lifetime of (possible) temporaries. curry (and its accompanying type, which is an implementation detail) is designed to be as lightweight as possible while still making it very, very safe to use. In particular, usage such as:

foo a;
bar b;
auto f = [](foo a, bar b, baz c, int) { return quux(a, b, c); };
auto curried = curry(f);
auto pass = curried(a);
auto some = pass(b);
auto parameters = some(baz {});
auto result = parameters(0);

does not copy f, a or b; nor does it result in dangling references to temporaries. This all still holds true even if auto is substituted with auto&& (assuming quux is sane, but that's beyond the control of curry). It's still possible to come up with different policies in that regard (e.g. systematically decaying).

Note that parameters (but not the functor) are passed with the same value category in the final call as when they're passed to the curried wrapper. Hence in

auto functor = curry([](foo f, int) {});
auto curried = functor(foo {});
auto r0 = curried(0);
auto r1 = curried(1);

this means that a moved-from foo is passed to the underlying functor when computing r1.

Community
  • 1
  • 1
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • 2
    +1 for the use of [..., ...](http://stackoverflow.com/questions/5625600/what-is-the-meaning-of-token) – Cubbi Jul 25 '12 at 12:34
5

With some C++14 features, partial application that works on lambda's can be implemented in a pretty concise way.

template<typename _function, typename _val>
auto partial( _function foo, _val v )
{
  return
    [foo, v](auto... rest)
    {
      return foo(v, rest...);
    };
}

template< typename _function, typename _val1, typename... _valrest >
auto partial( _function foo, _val1 val, _valrest... valr )
{
  return
    [foo,val,valr...](auto... frest)
    {
      return partial(partial(foo, val), valr...)(frest...);
    };
}

// partial application on lambda
int p1 = partial([](int i, int j){ return i-j; }, 6)(2);
int p2 = partial([](int i, int j){ return i-j; }, 6, 2)();
  • 1
    `rest` should be `auto&&...`, and used as `decltype(rest)(rest)...` not `auto...` and used as `rest...`. You should also capture-by-forward in C++14, which makes your second `partial` overload trickier. [live example](http://coliru.stacked-crooked.com/a/69e7c7249fa6c5a8). This avoids much of the needless copies your code does! – Yakk - Adam Nevraumont Sep 04 '15 at 00:21
0

A lot of the examples people provided and that i saw elsewhere used helper classes to do whatever they did. I realized this becomes trivial to write when you do that!

#include <utility> // for declval
#include <array>
#include <cstdio>

using namespace std;

template< class F, class Arg >
struct PartialApplication
{
    F f;
    Arg arg;

    constexpr PartialApplication( F&& f, Arg&& arg )
        : f(forward<F>(f)), arg(forward<Arg>(arg))
    {
    }

    /* 
     * The return type of F only gets deduced based on the number of arguments
     * supplied. PartialApplication otherwise has no idea whether f takes 1 or 10 args.
     */
    template< class ... Args >
    constexpr auto operator() ( Args&& ...args )
        -> decltype( f(arg,declval<Args>()...) )
    {
        return f( arg, forward<Args>(args)... );
    }
};

template< class F, class A >
constexpr PartialApplication<F,A> partial( F&& f, A&& a )
{
    return PartialApplication<F,A>( forward<F>(f), forward<A>(a) );
}

/* Recursively apply for multiple arguments. */
template< class F, class A, class B >
constexpr auto partial( F&& f, A&& a, B&& b )
    -> decltype( partial(partial(declval<F>(),declval<A>()),
                         declval<B>()) )
{
    return partial( partial(forward<F>(f),forward<A>(a)), forward<B>(b) );
}

/* Allow n-ary application. */
template< class F, class A, class B, class ...C >
constexpr auto partial( F&& f, A&& a, B&& b, C&& ...c )
    -> decltype( partial(partial(declval<F>(),declval<A>()),
                         declval<B>(),declval<C>()...) )
{
    return partial( partial(forward<F>(f),forward<A>(a)), 
                    forward<B>(b), forward<C>(c)... );
}

int times(int x,int y) { return x*y; }

int main()
{
    printf( "5 * 2 = %d\n", partial(times,5)(2) );
    printf( "5 * 2 = %d\n", partial(times,5,2)() );
}
SplinterOfChaos
  • 469
  • 3
  • 12
  • This code is a little dangerous because both F and Arg in the PartialApplication template could be deduced as references if partially applied functions are called with lvalues. Both F and Arg in the PartialApplication constructor are not universal references. std::forwarding them makes little sense. I would simply pass both by-value and std::move inside the constructor. The two argument function partial needs to use std::remove_reference from F and A types before passing on to the PartialApplication template. – Sumant Oct 15 '15 at 00:20