1.1 什么是函数式编程?
想给函数式编程下个明确的定义,是困难的。因为,存在不同的函数语言,但是,并没有明确的、每种函数语言必须具有的特征集。尽管如此,函数语言仍有一些共同的属性,只是表达解决编程问题的风格稍微有点不同。最容易地描述函数式编程,就是把它与最常见的编程风格:命令式编程(imperative programming),进行比较。
[函数语言]
函数式编程的编程风格是强调表达式计算,而不是执行命令。函数语言中的表达式是用函数组合成基本的值。[Hutton ed. 2002]
这一定义来自学术的邮件列表关于函数语言的常见问题解答(FAQ),所以它可能听起来有点抽象。相信我们,含义会很快变得清淅。第一句“表达式计算”是函数式表示,与命令式代码中的“执行命令”风格相对。命令式语言中的命令被称为语句(statements),因此,我们就用这个名词。让我们看看两者的详细内容:
■语句的执行:程序用一组命令,也称为语句表示。命令通过创建对象并操纵对象,实现最终结果。使用这种方法,通常使用可改变的对象,代码描述了需要执行什么操作才能达到所期望的结果。例如,我们首先制作一杯黑咖啡,这个对象是可改变的,因此,我们可以通过加两包糖以获得所需的结果。
■表达式计算:在函数式风格中,程序代码是描述对象属性的表达式,这个对象就是所需要的结果,不必要指定构造对象所需的步骤,在创建对象之前,是不可能意外使用的。例如,假设我们想要一杯加了两包糖的咖啡,在加糖之前我们是不能喝的,因为当我们得到这个杯子时,它已经包含了糖[唐军1] 1。
[
1 制作咖啡的类比, LucaBolognese 也曾经在 2009 年的 TechEd 有关 F# 的著名谈话中用过[Bolognese,2009]。这一巧合表明,通过学习函数式编程,你将学会以不同的方式思考,既包括编程问题,也包括下午休息。
]
这听起来差别可能很细微,但它会导致设计的代码方式的巨大变化。唯一的公理是我们写的代码是表达式,而不是语句序列,但这种方法有很多逻辑的后果。封装、组合代码的方式不同了,可以用多种技术写可重用的代码,使用更适合表示复杂计算结果的数据结构……清单可以一直写下去。
定义函数式编程是一回事,更需要理解的是如何把这些概念结合在一起,这两个主题构成本书的重点。你读完本书以后,不仅能理解前面的定义,而且对函数式编程的更直接。这才是更为重要的,遗憾的是,不是几句话就说得清的。
到目前为止,所有这一切听起来都很抽象,但这本书的标题包含的“实用(Real World)”是有充分理由的。函数式编程可以提供显著的好处。当遇到下面的情况,就可以用函数方式来解决(就像这本书的作者一样):
■你发现了吗,很难预测修改代码的后果,是由于隐蔽的依赖关系和微妙之处?
■你发现了吗,自己反复写相同的模式,没少有时间用于处理问题中真正不同和有意义的部分?
■你发现了吗,很难理清代码,担心代码是否每条语句都以正确的顺序,并在正确的条件下执行?
■你发现了吗,很难表达抽象的东西,它隐藏了代码是如何执行的,只指出了你想要实现什么?
■你发现了吗,异步控制流导致代码走向类似于意大利面条,令人抓狂?
■ 你发现了吗,很难把任务拆分成逻辑上独立的部分,能够同时运行多个处理器内核上?
■实际的代码行为与在单元测试中是否不同?
在我们正式了解函数式编程如何提高生产力之前,先简单地回顾一下其历史,那是相当的丰富。