现代C++19-函数式编程:一种越来越流行的编程范式

上一讲我们初步介绍了函数对象和 lambda 表达式,今天我们来讲讲它们的主要用途——函数式编程。

一个小例子

按惯例,我们还是从一个例子开始。想一下,如果给定一组文件名,要求数一下文件里的总文本行数,你会怎么做?

我们先规定一下函数的原型:

int count_lines(const char** begin,

const char** end);

也就是说,我们期待接受两个 C 字符串的迭代器,用来遍历所有的文件名;返回值代表文件中的总行数。

要测试行为是否正常,我们需要一个很小的 main 函数:

int main(int argc,

const char** argv)

{

int total_lines = count_lines(

argv + 1, argv + argc);

cout << "Total lines: "

<< total_lines << endl;

}

最传统的命令式编程大概会这样写代码:

int count_file(const char* name)

{

int count = 0;

ifstream ifs(name);

string line;

for (;;) {

getline(ifs, line);

if (!ifs) {

break;

}

++count;

}

return count;

}

int count_lines(const char** begin,

const char** end)

{

int count = 0;

for (; begin != end; ++begin) {

count += count_file(*begin);

}

return count;

}

我们马上可以做一个简单的“说明式”改造。用 istream_line_reader 可以简化 count_file 成:

int count_file(const char* name)

{

int count = 0;

ifstream ifs(name);

for (auto&& line :

istream_line_reader(ifs)) {

++count;

}

return count;

}

在这儿,要请你停一下,想一想如何进一步优化这个代码。然后再继续进行往下看。

如果我们使用之前已经出场过的两个函数,transform [1] 和 accumulate [2],代码可以进一步简化为:

int count_file(const char* name)

{

ifstream ifs(name);

istream_line_reader reader(ifs);

return distance(reader.begin(),

reader.end());

}

int count_lines(const char** begin,

const char** end)

{

vector<int> count(end - begin);

transform(begin, end,

count.begin(),

count_file);

return accumulate(

count.begin(), count.end(),

0);

}

这个就是一个非常函数式风格的结果了。上面这个处理方式恰恰就是 map-reduce。transform 对应 map,accumulate 对应 reduce。而检查有多少行文本,也成了代表文件头尾两个迭代器之间的“距离”(distance)。

函数式编程的特点

在我们的代码里不那么明显的一点是,函数式编程期望函数的行为像数学上的函数,而非一个计算机上的子程序。这样的函数一般被称为纯函数(pure function),要点在于:

会影响函数结果的只是函数的参数,没有对环境的依赖

返回的结果就是函数执行的唯一后果,不产生对环境的其他影响

这样的代码的最大好处是易于理解和易于推理,在很多情况下也会使代码更简单。在我们上面的代码里,count_file 和 accumulate 基本上可以看做是纯函数(虽然前者实际上有着对文件系统的依赖),但 transform 不行,因为它改变了某个参数,而不是返回一个结果。下一讲我们会看到,这会影响代码的组合性。

我们的代码中也体现了其他一些函数式编程的特点:

函数就像普通的对象一样被传递、使用和返回。

代码为说明式而非命令式。在熟悉函数式编程的基本范式后,你会发现说明式代码的可读性通常比命令式要高,代码还短。

一般不鼓励(甚至完全不使用)可变量。上面代码里只有 count 的内容在执行过程中被修改了,而且这种修改实际是 t

  • 43
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员zhi路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值