0x00问题引入
对于一个求自然数1-N和的问题,我们很容易写出以下递归公式:
f(n) = n == 1 ? 1 : n + f(n - 1);
若想使用C++lambda表达式实现上述过程,我们很容易将其改写为以下代码:
const auto& f = [](const int& n) {
return n == 1 ? 1 : n + f(n - 1);
};
发现编译无法通过,为什么呢?原因是,由于lambda表达式的匿名特性,无法直接在lambda内部递归调用lambda,我们需要另寻其道来解决该问题。
0x01使用std::function
std::function可以把lambda包装起来,相当于赋予了其一个函数名,在通过引用捕获并实现递归调用,实现如下:
const auto& sum1 = [](const int& n) {
std::function<int(const int&)>s;
s = [&](const int& n) {
return n == 1 ? 1 : n + s(n - 1);
};
return s(n);
};
0x02将lambda作为参数
先附上代码:
const auto& sum2 = [](const int& n) {
const auto& s = [&](auto&& self, const int& x) -> int{
return x == 1 ? 1 : x + self(self, x - 1);
};
return s(s,n);
};
注意到,调用s(s,n)时,我们把lambda表达式本身作为了参数传入来实现递归调用。
0x03使用Y组合子
构造一个Y组合子如下:
const auto& y = [](const auto& f) {
return [&](const auto& x) {
return x(x);
}([&](const auto& x) -> std::function<int(int)> {
return f([&](const int& n) {
return x(x)(n);
});
});
};
再实现一个求和函数的高阶函数如下:
const auto& sum3 = [](const auto& f) {
return [=](const int& n) {
return n == 1 ? 1 : n + f(n - 1);
};
};
然后连接即可。
0x04测试
在main中简单测试一下上述实现:
int main() {
std::cout << sum1(100);//print 5050
std::cout << sum2(100);//print 5050
std::cout << y(sum3)(100);//print 5050
}
运行结果符合预期。