在计算机时代的早期,内存既稀缺又珍贵,为了让程序适应有限的内存,程序员往往会在程序执行时修改内存中的代码,使程序做些不一样的事情,来节省代码空间。这就是所谓的“自修改代码”技术。而且只要程序小到可以只需要少部分人就能维护所有晦涩难懂的汇编代码,让它运行起来多半不是什么大问题
内存越来越便宜,处理器也越来越快。C语言出现了,而且它被大多数汇编语言程序员认为是“高级语言”。其他人发现,C语言可以大大提升他们的工作效率。而且在使用C语言时,创建自修改代码仍然不是那么困难
随着硬件越来越便宜,程序的规模和复杂性也不断增加。单单是让程序工作起来就已经变得很困难了。我们想方设法地让代码更加一致和易懂。就其最纯粹的形势而言,自修改代码已被证明是非常糟糕的想法,因为很难确定这些代码是在做什么,测试它们也很困难。
然而,使用代码以某种方式操纵其他代码这种想法仍然非常吸引人,只要有某种方法使其更加安全即可
从代码创建、维护和可靠性的角度来看,这个想法很有吸引力。试想一下,我们不是从零开始编写大量代码,而是从现有的、可以理解的、经过良好测试的、可靠的小代码片段开始。然后将它们组合在一起,创建新的代码
这就是函数式编程(functional programming, FP)的意义所在。通过整合现有代码来产生新的功能,而不是从零开始编写所有内容,由此我们会得到更可靠的代码,而且实现起来更快。这个理论看起来是成立的,至少在某些情况下如此。在发展过程中,函数式语言设计出了优秀的语法,一些非函数式语言也借用了
我们也可以这样认为:
面向对象编程抽象数据,而函数式编程抽象行为
纯函数式语言在安全方面做出了更多努力。它规定了额外的约束条件,即所有的数据必须是不可变的:设置一次,永不改变
函数会接收值,然后产生新值,但是绝对不会修改自身之外的任何东西(包括其参数或该函数作用域之外的元素)
有了这一保证,我们知道不会再有任何由所谓的“副作用”引起的bug,因为函数只是创建并返回了一个结果,别的什么都没做
更妙的是,“不可变对象和无副作用”这一编程范式解决了并行编程(当程序的不同部分同时在多个处理器上运行)中最基本和最棘手的问题之一——“可变的共享状态”问题
“可变的共享状态”意味着,运行在不同处理器上的代码的不同部分,可能会同时尝试修改同一块内存(谁会成功?没有人知道)
如果函数绝对不会修改现有值,而只是生成新值——这是纯函数式语言的定义——那么就不可能存在对内存的竞争
因此,纯函数式语言经常被当作并行编程问题的解决方案,当然也有其他可行的解决方案
还要记住,支持函数式编程的理由,特别是程序员能以更快的速度创建更稳健的代码,至少在一定程度上还只是假设。我们已经看到了一些好的结果,但是我们还没有证明纯函数式语言就是解决这类编程问题的最佳方法