函数式编程与程序的本质
变量的类型实现了对变量的约束,这种约束可以防止人犯一些愚蠢的错误。早期的计算机内存制造成本是很高的,一块内存需要反复使用,所以变量就显得很必要了。
这也是为什么早期函数式语言很难发展起来,函数式语言中,变量值是不可变的,对值的操作并不是修改原来的值,而是修改新产生的值,原来的值保持不变。同样由于变量不可变,纯函数编程语言无法实现循环,这是因为 for 循环使用可变的状态作为计数器,而 while 循环或 do while 循环需要可变的状态作为循环的条件。因此在函数式语言里就只能使用递归来解决迭代问题,这使得函数式编程语言严重依赖递归。
程序的本质就是一头有输入,而另一头有输出,但关键是从输入到输出的这个映射十分复杂。面向对象的方法是将处理职责拆分到不同的类,然后组合和复用这些类来构建程序,但如何拆分和如何给这些细小部分的处理职责定个类名?没有标准答案,这也是 OO 系统混乱的根源,所以早期为了解决系统混乱,软件工程告诉我们要从业务角度去拆分,所以软工必修 UML,用于系统分析设计,但人们抛弃了 UML,说我们要敏捷!先定义表再定义类,一大堆 getter、setter,再写上一堆 mapper 的废物注解,然后喊我们是面向对象。现在2020年了,依旧如此。另一方面,函数式的作法就更加贴近计算与组合的本质,它将这个复杂的映射体拆分程小的映射体,这些映射体都以计算来命名,比如一个 toUpperCase function,我明确知道这是一个我给它一个字符串,它还我一个将所有英文字符转为大写的字符串,函数式编程就是通过组合这些细小的映射体来构建复杂的映射体,所以组合才是 functional programming 的本质,这时候会有人喊 Monad?范畴论?扯皮!写 FP 根本不需要理解范畴论,Monad 的存在,是因为我们输入与输出有时候是不定的、不具体的,它们需要修饰词,比如 null 处理,异常处理,所有才会有 Maybe 和 Either。什么?纯度处理?IO?魔怔?追求纯粹?在计算机世界里,最初的输入与最终的输出不可能是纯的!副作用总是真是存在,我们说的复杂是指构建这整个大的映射体的逻辑组合的复杂,而不是区纠结最终和最初到底是不是纯!