起因

最初看到函数式编程的东西是在知乎等地方看到关于Lisp的材料,后来又断断续续的看到了很多的相关面试题,比如如何不用循环处理XX问题。不过这时候还没有在意,真正让我感兴趣的是在学Rust的时候(关于学Go和Rust的过程后续再讲)有人说到Rust的模板匹配、Option设计是函数式很好的被借鉴过来的特性,这就让我感到非常好奇。顺着这个思路,我就去学了一下Coursera上的华盛顿大学的Programming Language课,确实有许多收获,不枉此行。


关于这门课

首先说这门课完全免费(想要证书除外),可以参与在线提交作业等一切活动。从内容上来说,我个人认为适合已掌握至少两门语言、算法基础过关的中等以上开发者去学,否则很难体会其中一些精妙之处。

这门课的学习过程与我以往在Coursera上的学习不同,由于工作比较忙,很难有大把时间去坐下来听老师所讲。正好这门课每周都会有一个集大全的总结文档,我就打印下来在些许有空的时候去翻翻看,最终结果是几乎80%的视频我都没有看,但最后实际上是用了两倍的时间才完成这门课。


一些体会

函数式编程要说一个具体的定义,怕是很难去界定,包括这门课的老师也没有给出一个准确的定义,不过倒是有一些大概的特点。比如说

  • 对于递归解决问题的偏爱函数
  • 作为一等公民可以传递
  • 偏向于使用不可变变量

等等

它这么设计能带来什么好处?

写了一些并不实用的代码后有一些小小的体会:使用高度抽象的方式来解决问题会减少大量的重复代码甚至是重复模式,写得少就错的少。使用不可变变量从一定程度上可以让人少犯很多新手时的错误,比如一个可迭代对象一边迭代一边删除的有趣场景?同时不可变变量会帮助相同函数应用于一批对象的时候没有那么多锁的限制也可以保证正确性。

学习它对于实际编程的影响?

大概是从一个更多元的角度来思考编程,并且理解了很多语言中的借鉴。比如说Python自带了map和filter、闭包,如果用得好是可以玩出很多花样的。比如说Rust中Option+模板匹配的设计,完全避免了我们想表达空值、又受限于规定的返回值类型,不得不人为指定一个空值的场景。在这种场景下,实现表达空值是不困难的,但编译器完全对此无法检查,如果调用方不去手动检查是否为空值,那么问题就产生了。我觉得像Rust的这个特性引入是非常优秀的,只有在真正用过这些东西之后才能觉察到之前为了那些条条框框做出的那么多妥协!

什么地方可以用到函数式?

我个人倒是觉得大可不必真的全部都按照函数式的方法去写每一段业务,该用for循环就用for,该面向对象自然还是要面向对象的。不过在一些特定场景下,用函数式的方法有明显的优势,举几个栗子:

你的一个文件夹下有很多文件或者文件夹,文件夹下递归的还有很多文件和文件夹,你想对这个文件夹下的所有递归的HTML文件都替换一个链接。那么把替换操作封装成一个函数,参数为文件句柄,然后主函数仅负责递归和调用这个函数。这样一来,如果哪一天又想删除某个特定链接,大可仅改动很小的函数代码,即可实现。(这是我曾经真的实现的一个现实需求)

Python里日常的排序操作,假如有tup_list = [("a",1),("b",-1),("c",2)],想要按照每个元组里的数字排序,借助sort+匿名函数的方法我觉得是最优雅的实现:tup_list.sort(key=lambda x:x[1])

先写这么多,也许后续会再写些更具体的内容。