I'm trying to write the “plus2” and “plus3” functions that implement the functions, respectively, and are defined as follows.
f is a function such that expression (x) (y) should result in the value of x y.
g is a function such that expression (x) (y) (z) should result in the value of x y z. Here, x, y, z are integers.
#include <functional>
#include <iostream>
std::function<int(int)> plus2(int n) {
return [n](int x) { return x n; };
}
std::function<int(int)> plus3(int f(int), int n) {
return [f, n](int x) { return f(n) x; };
}
int main() {
std::cout<<plus2(1)(2)<<" "<<plus3(1)(2)(3);
return 0;
}
OUTPUT should be: 3 6
I get an error
too few arguments to function ‘std::function<int(int)> plus3(int (*)(int), int)’
Function plus2 works fine. Could you explain me where I'm making mistake in function plus3?
CodePudding user response:
Function plus2 works fine.
Because plus2
is a function that expects 1 parameter and returns a function that expects 1 parameter.
plus3
on the other hand is a function that expects 2 parameters. You cannot call it with only one parameter. You can turn it into a function that expects one parameter and returns a callable that returns a callable.
I suppose this is just an exercise to learn lambdas, because otherwise I see no reason to write the functions like this. At least you should use auto
return type to avoid unnecessary conversion to std::function
(*):
#include <iostream>
auto plus3(int n) {
return [n](int a) { return [b=a n](int c){ return b c;} ;};
}
int main(int argc, char* argv[]){
std::cout << plus3(1)(2)(3);
}
(*): std::function
is not the type you should use whenever you want to pass a callable around. Rather it is the type to be used when you need one type that can store any kind of callable. std::function
uses type erasure to achieve that. If you do not need that then you do not need std::function
.
CodePudding user response:
It looks like you are practicing the subject of currying in functional programming (Currying - Wikipedia).
If you want to write plus3
as a curried function you can do the following (no change in plus2
):
#include <functional>
#include <iostream>
auto plus2(int n) {
return [n](int x) { return x n; };
}
auto plus3(int n) {
return [n](int m) {
return [n, m](int x) { return x n m; }; };
}
int main() {
std::cout << plus2(1)(2) << " " << plus3(1)(2)(3);
return 0;
}
CodePudding user response:
plus3
should take an int
and produce a function.
It should not take a function and an int
.
The resulting function should take an int
and then proceed as plus2
.
It's a nice touch to reuse plus2
:
std::function<std::function<int(int)>(int)> plus3(int n) {
return [n](int x) { return plus2(n x); };
}
Slightly more readable with a type alias:
using int_to_int = std::function<int(int)>;
std::function<int_to_int(int)> plus3(int n) {
return [n](int x) { return plus2(n x); };
}
and now you can generalize:
template<size_t n>
auto plus(int x)
{
return [x](int y) { return plus<n-1>(x y); };
}
template<>
auto plus<1>(int x) { return x; }
int main() {
std::cout << plus<2>(1)(2) << std::endl << plus<4>(1)(2)(3)(4) << std::endl;
}