Home > database >  Simplest case of currying with a lambda is illegal
Simplest case of currying with a lambda is illegal

Time:10-21

The textbook functional programming introduction example "return a function with a curried parameter" in C does not compile for me:

// return a function x(v) parameterized with b, which tells if v > b
bool (*greater(int))(int b) 
{
    return [b](int v) { return v > b; };
}

It says that identifier b in the capture [b] is undefined. I know that I'm being naive here, but where is my error?

CodePudding user response:

You say that greater is a function taking an unnamed (anonymous) int argument, and return a pointer to a function taking an int argument with the name b.

The part (int b) is the argument list for the returned function pointer.

To solve that specific problem use

bool (*greater(int b))(int)

instead.

Because function pointers are so complicated, they are usually hidden behind type-aliases:

using greater_function_type = bool(int);
greater_function_type* greater(int b) { ... }

As for the problem that lambdas with captures can't be used as C-style function pointers, use std::function as return type instead:

using greater_function_type = std::function<bool(int)>;
greater_function_type greater(int b) { ... }

Note that it's not returning a pointer anymore.

Since the C 14 standard you can use automatic return-type deduction with the keyword auto:

auto greater(int b) { ... }

If you need to store the returned objects, for example as a class member variable, you need to use std::function<bool(int)> for that.


Also be careful when using names like greater in conjunction with using namespace std; (which is a bad habit), because of std::greater.

CodePudding user response:

Lambda is capturing [b], which cannot be converted to a function pointer. It requires std::function:

std::function<bool(int)> greater (int b) { ... }

If the function is expected to be inline then you may use simple auto as well:

auto greater (int b) { ... }

BTW, if b is not expected to change within the scope of greater(), then accept it as const int b instead f int b to be more expressive.

CodePudding user response:

Only lambdas without capture can be cast into a C style function pointer.
Lambdas with capture are actually classes with data members (one for each capture).
In your case you have one capture (b).

In order to return a curried function (which require a capture) you should use std::function:

#include <functional>
#include <iostream>

std::function<bool(int)> greater(int b)
{
    auto l = [b](int v) { return v > b; };
    return l;

}

int main()
{
    auto g5 = greater(5);
    std::cout << g5(2) << std::endl;
    std::cout << g5(7) << std::endl;
}

Output:

0
1
  • Related