结构化编程和面向对象编程都革新了业务应用程序构建的方式。但是还存在其他编程模型,有些梦想家还认为这些范式比面向对象编程的生产力更高。这篇文章探索 Haskell 研究函数性编程的基础。学习函数性编程可以重塑对于 Java? 编程的思考方式。

过去 50 年中,企业所使用的语言 —— COBOL、C、C++ 和 Java 语言,都是命令式 语言;它们让您告诉您的程序如何 去完成其任务。函数性 编程语言让您告诉程序去做什么。这篇文章通过介绍 Haskell 来研究函数性编程。(如果您阅读过我的跨越边界 系列中 关于使用另外一种函数性语言 Erlang 进行并发性编程的文章,可能已经有了一定的基础。)

在我研究超越 Java(请参阅 参考资料) 时,我采访的三位专家提到了 Haskell,他们认为我应该探索一下这种语言。当时,我并不认为市场已经为函数性编程做好了准备,因为这一范式对于大多数程序员来说都太陌生了。我现 在仍然不认为我们已经做好了准备。但是我开始欣赏函数性语言带来的生产力和强大力量。我只是刚刚接触 Haskell,但这种语言已经影响了我使用 Java 和 Ruby 语言解决问题的方式。

命令式语言及其不足

命令式编程由一系列带有明确顺序的语句构成,它们的算法和编程构造严重依赖于应用程序的状态。很难想像没有这些特征的编程语言,因为命令式语言 “告诉我如何做” 的方式是如此深刻地确立在我们的日常编程哲学中。命令式编程明确塑造了您的思维方式。但通过学习替代的函数性编程工具,可以扩展您思考问题的方式。请考虑 以下这些命令式结构:

· 赋值。命令式编程的用户对赋值的依赖要超过其他编程技术。函数性编程最多允许为每个变量赋值一次。改变值的赋值被叫做 破坏性赋值,是不允许的。例如,多数函数性语言不允许 x = x + 1。

· 迭代。命令式编程利用迭代来处理许多不同类型的数据结构。许多命令式控制依赖破坏性赋值进行迭代。

· 副作用。在命令式语言中,输入相同而可能返回不同值的方法,都有副作用。而对应用程序的状态变量有影响的方法也有副作用。函数性编程没有副作用。

如果以前没用过函数性语言,那么就很难想像如何编写没有破坏性赋值和副作用的应用程序。但是这些基本特征给命令性语言带来了一些更严重的问题:

· 正确性问题。有副作用的方法可能返回一个值,但同时也修改了应用程序的状态。副作用把验证程序正确的数学问题复杂化。但是复杂不仅仅是数学问题:副作用还使得测试、理解、分析和记录程序的行为更加困难。

· 基于顺序的 bug。许多优化依赖于对关键编程指令重新排序来提高性能。当依赖特定顺序的程序被重新排序时,错误就发生了。

· 并发性问题。可变状态消失时,差不多所有的并发性问题也随之消失。Brian Goetz 在 Java Concurrency in Practice(请参阅 参考资料)中,用 “这是愚蠢的可变状态“ 规则结束了第一章。

不管信还是不信,不必强行规定操作的顺序或承担副作用,也可以有效地编程。

函数性编程简介

在数学中,函数把每个输入映射到一个特定的输出。函数性编程范式使用数学函数表达程序。函数性语言并不执行命令,而是通过表示、计算数学函数来解决问题。函数性语言通常有以下两个特征:

· 不可变的数据。纯粹的函数性语言不依赖保存或检索状态的操作,因此不允许破坏性赋值。

· 无副作用。用相同的输入调用函数,总是返回相同的值。

对大多数函数性语言来说,这有点过于简化,但是只是过了一点点。函数叫做单体(monad,被用来以数学方式表达状态的变化,而 Haskell 这样的函数性语言则用单体来处理输入/输出并管理状态中的变化。

看到函数性编程的一些局限性后,您可能认为这种编程范式是一种倒退,但请继续往下阅读。函数性语言不是软弱无力的。实际上,语言专家们通常相信函数 性语言操作的抽象级别要比面向对象语言高。它们提供了命令式语言通常不提供的一些工具。在这篇文章中,将看到一些工具的工作效果。

使用 Haskell

有两个 Haskell 实现值得注意:Hugs 和 Glasgow Haskell Compiler(GHC)(请参阅 参考资料)。 还有许多其他 Haskell 编译器和解释器,包括 Hugs 和 GHC 的分支,但是它们是主要的两个。如果刚接触 Haskell,那么 Hugs 解释器是个不错的选择,因为它安装和理解起来都比较容易。Hugs 有两方面严重的限制:它缺乏编译器,不能使用独立函数;必须从文件装入全部函数。更严谨的程序员会采用 GHC。它的解释器略慢一些,但是它有编译器模式,还允许独立函数。在这篇文章中,我使用 Hugs,所以如果您想根据本文编写代码,也应当使用它,因为这两套软件使用的术语略有不同。

用 Hugs 编码

请下载适合您操作系统的 Hugs (请参阅 参考资料)并启动它。我把我信任的 Macbook Pro 放在一边,而用我的 Windows 机器,这是为了得到一个可以快速安装的环境。WinHugs 这个 Hugs 实现在 Windows 平台上有一个简单的一按即可的安装程序。

将看到一个带有 Hugs 提示符的解释器窗口。启动即可。输入一些数字和数学表达式,如清单 1 所示。将看到 Hugs 返回数学表达式的结果。这正是在函数性语言中期待的行为。