C++ 函数式编程:高级技术与示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C++ 函数式编程:高级教程

\n\n

函数式编程(FP)是一种将计算视为数学函数求值,并避免可变状态和副作用的编程范式。尽管 C++ 传统上与面向对象和过程式编程相关联,但现代标准(C++11 及更高版本)引入了强大的工具来编写函数式代码。在本文中,我们将超越基本的 lambda,探讨高级技术:从函数组合到单子模拟。

\n\n

1. 函数组合与管道

\n\n

函数组合是将两个或多个函数合并以创建一个新函数的过程。在 C++ 中,使用 lambda 表达式和模板可以方便地实现这一点。

\n\n
#include <iostream>\n#include <functional>\n#include <vector>\n#include <algorithm>\n\n// 两个函数组合的模板\ntemplate<typename F, typename G>\nauto compose(F f, G g) {\n    return [f, g](auto x) {\n        return f(g(x));\n    };\n}\n\n// 使用示例\nint main() {\n    auto addTwo = [](int x) { return x + 2; };\n    auto multiplyByThree = [](int x) { return x * 3; };\n\n    // 组合:先 multiplyByThree,再 addTwo\n    auto composed = compose(addTwo, multiplyByThree);\n\n    std::cout << composed(5) << std::endl; // (5*3) + 2 = 17\n\n    // 使用 std::ranges 进行管道处理(C++20)\n    std::vector<int> numbers = {1, 2, 3, 4, 5};\n    auto result = numbers\n        | std::views::filter([](int n) { return n % 2 == 0; })\n        | std::views::transform([](int n) { return n * n; });\n\n    for (int n : result) {\n        std::cout << n << " "; // 4 16\n    }\n    return 0;\n}\n
\n\n

使用 std::views(C++20)的管道允许构建转换链而无需创建中间容器,这是一种经典的函数式方法。

\n\n

2. 柯里化(Currying)与部分应用

\n\n

柯里化是将一个接受多个参数的函数转换为一系列函数,每个函数只接受一个参数。部分应用则固定部分参数。

\n\n
#include <iostream>\n#include <functional>\n\n// 柯里化的加法函数\nauto curriedAdd = [](int a) {\n    return [a](int b) {\n        return [a, b](int c) {\n            return a + b + c;\n        };\n    };\n};\n\n// 使用 std::bind 进行部分应用\nint multiply(int a, int b, int c) {\n    return a * b * c;\n}\n\nint main() {\n    // 使用柯里化\n    auto add5 = curriedAdd(5);\n    auto add5And3 = add5(3);\n    std::cout << add5And3(2) << std::endl; // 10\n\n    // 通过 std::bind 进行部分应用\n    using namespace std::placeholders;\n    auto multiplyBy2 = std::bind(multiply, _1, _2, 2);\n    std::cout << multiplyBy2(3, 4) << std::endl; // 3*4*2 = 24\n\n    // 通过 lambda 进行部分应用(在 C++14+ 中更地道)\n    auto multiplyBy3 = [](int a, int b) { return multiply(a, b, 3); };\n    std::cout << multiplyBy3(5, 6) << std::endl; // 5*6*3 = 90\n\n    return 0;\n}\n
\n\n

柯里化在与高阶函数(如 std::transform 或 std::accumulate)一起使用时特别有用,允许“即时”创建函数的特化版本。

\n\n

3. 函子、应用函子与单子模拟

\n\n

在 Haskell 中,单子是一种处理副作用的强大模式。在 C++ 中,我们可以使用类模板来模拟它们。考虑一个简单的 Maybe 单子(类似于 std::optional),但带有单子操作。

\n\n
#include <iostream>\n#include <functional>\n#include <optional>\n\n// Maybe 单子(std::optional 的包装器)\ntemplate<typename T>\nclass Maybe {\n    s                

博客

书籍推荐