Functional programming in C++. Implementing f(a)(b)(c)

Solution 1:

You can do it by having your function f return a functor, i.e., an object that implements operator(). Here is one way to do it:

struct sum 
{
    double val;

    sum(double a) : val(a) {}

    sum operator()(double a) { return val + a; }

    operator double() const { return val; }
};

sum f(double a)
{
    return a;
}

Example

Link

int main()
{
    std::cout << f(1)(2)(3)(4) << std::endl;
}

Template version

You can even write a templated version that will let the compiler deduce the type. Try it here.

template <class T>
struct sum 
{
    T val;

    sum(T a) : val(a) {}

    template <class T2>
    auto operator()(T2 a) -> sum<decltype(val + a)> { return val + a; }

    operator T() const { return val; }
};

template <class T>
sum<T> f(T a)
{
    return a;
}

Example

In this example, T will ultimately resolve to double:

std::cout << f(1)(2.5)(3.1f)(4) << std::endl;

Solution 2:

Just take your 2 elements solution and expand it, by wrapping it with another lambda.

Since you want to return a lambda that get a double and returns a doubles' addition lambda, all you need to do is to wrap your current return type with another function, and add a nested lambda into your current one (a lambda that returns a lambda):

std::function<std::function<double(double)>(double)> plus3 (double a){
    return [a] (double b) {
        return [a, b] (double c) {
            return a + b + c;
        };
    };
}

  • As @Ðаn noted, you can skip the std::function<std::function<double(double)>(double)> and get along with auto:

    auto plus3 (double a){
        return [a] (double b) {
            return [a, b] (double c) { return a + b + c; };
        };
    }
    
  • You can expand this structure for every number of elements, using deeper nested lambdas. Demonstration for 4 elements:

    auto plus4 (double a){
        return [a] (double b) {
            return [a, b] (double c) {
                return [a, b, c] (double d) {
                    return a + b + c + d;
                };
            };
        };
    }
    

Solution 3:

Here is a slightly different approach, which returns a reference to *this from operator(), so you don't have any copies floating around. It is a very simple implementation of a functor which stores state and left-folds recursively on itself:

#include <iostream>

template<typename T>
class Sum
{
    T x_{};
public:
    Sum& operator()(T x)
    {
        x_ += x;
        return *this;
    }
    operator T() const
    {
        return x_;
    }
};

int main()
{
    Sum<int> s;
    std::cout << s(1)(2)(3);
}

Live on Coliru

Solution 4:

This isn't f(a)(b)(c) but rather curry(f)(a)(b)(c). We wrap f such that each additional argument either returns another curry or actually invokes the function eagerly. This is C++17, but can be implemented in C++11 with a bunch of extra work.

Note that this is a solution for currying a function - which is the impression that I got from the question - and not a solution for folding over a binary function.

template <class F>
auto curry(F f) {
    return [f](auto... args) -> decltype(auto) {
        if constexpr(std::is_invocable<F&, decltype(args)...>{}) {
            return std::invoke(f, args...);
        }
        else {
            return curry([=](auto... new_args)
                    -> decltype(std::invoke(f, args..., new_args...))
                {
                    return std::invoke(f, args..., new_args...);
                });
        }
    };  
}

I've skipped forwarding references for brevity. Example usage would be:

int add(int a, int b, int c) { return a+b+c; }

curry(add)(1,2,2);       // 5
curry(add)(1)(2)(2);     // also 5
curry(add)(1, 2)(2);     // still the 5th
curry(add)()()(1,2,2);   // FIVE

auto f = curry(add)(1,2);
f(2);                    // i plead the 5th