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 double
s' 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 withauto
: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