Skip to content

Functional Programming

语法

transform

#include <algorithm>
#include <vector>

std::vector<int> v{1,2,3};
std::vector<int> out(v.size());
std::transform(v.begin(), v.end(), out.begin(),
               [](int x){ return x * 2; });
// out = {2,4,6}

copy_if

#include <algorithm>
#include <vector>

std::vector<int> v{1,2,3,4,5};
std::vector<int> odds;
std::copy_if(v.begin(), v.end(), std::back_inserter(odds),
             [](int x){ return x % 2 == 1; });
// odds = {1,3,5}

accumulate

#include <numeric>
#include <vector>

std::vector<int> v{1,2,3,4};
int sum = std::accumulate(v.begin(), v.end(), 0,
                          [](int a,int b){ return a + b; });

views

#include <ranges>
#include <vector>
#include <iostream>

std::vector<int> v{1,2,3,4,5,6};

auto view = v
  | std::views::filter([](int x){ return x % 2 == 0; })
  | std::views::transform([](int x){ return x * x; });

for (int x : view) std::cout << x << " "; // 4 16 36
  • views::filter(pred):过滤

  • views::transform(f):映射

  • views::take(n) / views::drop(n):取前 n / 跳过前 n

  • views::take_while(pred) / views::drop_while(pred):按条件截断

  • views::reverse:反向

  • views::split(delim):按分隔符拆分(字符串处理很常用)

#include <ranges>
#include <string_view>
#include <iostream>
#include <string>

int main() {
  std::string_view s = "a,b,cc";

  auto parts = s | std::views::split(',');

  for (auto sub : parts) {
    std::string token(sub.begin(), sub.end()); // sub 是一段字符 range
    std::cout << "[" << token << "] ";
  }
  // [a] [b] [cc]
}
  • views::join:把 range-of-ranges 拉平

  • views::iota(a, b):生成序列(像 Python 的 range)

  • views::enumerateC++23 才有(有的库实现已提供)用于 (index, value) 风格

  • sort

#include <ranges>
std::ranges::sort(v);

练习

Week 1:FP 基础(map / filter / reduce)

  1. Map:把一串整数映射为平方(保序)
  2. Filter:筛出素数(写纯 is_prime(int)
  3. Reduce:求和、求最大值、求乘积(空输入要处理)
  4. 组合:先 filter 偶数再 map 平方再 sum(用 views pipeline)
  5. 词频统计:给定字符串列表,统计单词出现次数(注意纯化:分词函数独立)
  6. Top-K:词频 top 10(尽量用 ranges + partial_sort / nth_element)
  7. 去重:稳定去重(保留首次出现)与非稳定去重(排序+unique)对比
  8. 函数组合:写一个 compose(f,g)compose(f,g)(x)=f(g(x))(模板+完美转发)

Week 2:Ranges 进阶(惰性视图 + 管道表达)

  1. 解析→过滤→变换:从一行 CSV(逗号分隔)解析数字,过滤非法/空,转成 int,再统计均值
  2. 滑动窗口:计算 moving average(窗口大小 N,输出序列)
  3. 相邻差分:输出 a[i+1]-a[i](空/单元素处理)
  4. Run-length encoding:把 aaabcc 编码成 a3b1c2(尽量用 ranges 思路组织)
  5. 区间合并:输入若干 [l,r] 合并重叠区间(排序后 fold)
  6. “惰性”练习:实现一个 view/pipeline:读入序列后只在最终消费时才计算(用 views,不要提前 materialize)
  7. zip-like:用索引实现“带下标 map”((i,x)->...),体验“enumerate”风格

Week 3:函数式“错误处理”(optional / variant / expected)

(这周重点是把“失败”当值传递,避免到处 throw 或返回魔法值)

16) parse_int:返回 std::optional<int>,支持前后空格、符号、溢出检测 17) 链式处理optional 的管道:解析→校验范围→映射(你自己写 and_then / transform / or_else 小工具) 18) 表达多种错误:把 parse_int 改成 std::expected<int, ParseError>(C++23) 19) 组合 expected:实现 map_expected / and_then_expected,让多步解析可以一行链起来 20) 配置加载:输入多行 key=value,解析成 map;遇到重复 key 或非法行,用 expected 返回详细错误 21) 业务规则评估:一组规则函数 Rule: T->expected<Score,Err>,把它们组合成总评分(fold) 22) variant 分派:写一个表达式 AST(数字/加/乘/括号),用 std::variant + std::visit 做纯求值


Week 4:更“函数式”的工程化写法(性能+可维护)

  1. std::function 的高阶函数:写一个 apply_all(fns, x),其中 fns 是一组 callable(模板参数/auto),返回依次应用结果
  2. 策略组合:排序策略(按姓名/按年龄/按多字段),用函数对象组合比较器(then_by 风格)
  3. 不可变数据建模:实现一个 struct(只读字段)+ 一组 with_xxx 返回修改后的副本(练“持久化”思路)
  4. 数据流水线项目:日志分析:输入多行文本 → 解析字段 → filter → group by → top-K(把每一步写成独立纯函数)
  5. 性能练习:同一题写 2 版:

  6. A:全 ranges/views 组合

  7. B:手写循环 用基准测试对比(理解“抽象成本”与何时该退回循环)

  8. 并行友好 reduce:写一个结合律友好的聚合(比如计数/求和/最值),对比不结合的例子(理解并行 reduce 的坑)

  9. 边界层隔离:把上面的“日志分析”做成:parse -> compute -> render 三层,只有 render 做 IO
  10. 小库封装:把你写过的 compose/and_then/transform 整理成一个头文件 fp.hpp,给每个函数补 5 行文档注释 + 单测