首页 > 代码库 > 为什么函数式编程是重要的 --1

为什么函数式编程是重要的 --1

声明: 本译文只是为了提高个人英语阅读能力, 网上有更多精彩的翻译. 对于我这个英语水平极差的人來说, 翻译是十分痛苦的, 希望体谅. 原文请见 ^_^

Why Functional Programming Matters

这篇文章的数据来自 1984年, 作为 Chalmers 的备忘录传播多年. 稍微改变的版本出现在 1989年 和 1990 年. 这个版本是建立在原来 Chalmers 备忘录的基础上, 轻微地用 LaTeX 改动 使得它更接近发布 版本.

概要

一个软件变得越来越复杂, 那么对他组织得好就变得越来越重要. 好的结构 使更容易去写程序, 更容易去调试程序, 并且提供一个 能够重用的模块的集合 來减少未来的编码支付. 传统的语言在 模块化上有 概念上的限制. (Conventional languages place concetual limits on the way problems can be modularised.) 函数式语言没有这些限制, 他能 做到更大限度的模块化. 比如, 我们处理链表和树, 编写几个数值算法, 并且处理 alpha-beta 启发式 (一个人工只能的算法, 用于游戏编程中). 自从模块化成为 编程的关键, 函数式语言对现实世界是及其重要的.

介绍

这篇文章目的是证明 函数式编程 对于 现实世界是及其重要的 并且通过清楚的指出函数式语言 的优点帮助函数式编程的程序员探索他的全部优点.

之所以叫函数式编程是因为一个程序全部由函数组成. 主程序被写成一个來接受程序的输入作为 他的参数并且传递程序的输出作为他的结果的函数.

代表性的是主函数由其他函函定义, 其他函数轮流被其他函数定义, 直到底部函数是原始的语言. 这些函数更像是原始的数学函数, 并且在这篇文章中将会通过原始的等式定义. 我们的符号标记 来自 Turner 的语言 Miranda(TM), 但对于没有函数式语言基础的读者也是可读的.

函数式编程的特殊和优点经常被或多或少的总结出如下几点:函数式编程没有赋值语句, 所以 编程, 一旦我们给了一个值, 就不会被改变. 更通常的来说, 函数式编程没有副作用. 一个 函数调用除了计算他的值之外没有其他作用. 这消除了主要 bugs 的根源, 并且由于没有副作用 來改变表达式的值也让程序的执行和顺序无关, 因为他能够在任何时候被计算. 这减轻了编程的 所规定的控制流的负担. 由于表达式能在任何时候被求值, 我们能自由地用变量的值來取代变量, 反之也成立. 程序是引用透明的, 这种自由能帮助函数式程序更容易数学上的控制比其他传统的 语言.

这些优点都是很好的, 但我们也不会惊讶如果外行人对此毫不在乎. 听起来很多关于函数式编程的 是他所没有的 (没有赋值, 没有副作用, 没有控制流) 但没有更多关于他有什么. 函数式程序员 听起来像是和尚, 禁绝了乐趣的生活希望他们变得高尚. 对于那些对追求表面利用的人来说, 这些 "优点" 好像没有什么值得信服的.

函数式程序员会争论道 函数式编程能带来很多的 利益. 函数式程序员比其他类型语言的程序员 更高产, 因为函数式程序更短小. 为什么这是正确的? 一个好像有道理的原因是传统的程序由 90% 的赋值语句, 但是在函数式程序中, 这些赋值能被省略. 这是明显可笑的. 如果省略赋值 语句能带来如此大的收获, 那么 FORTRAN 程序员20年前早就这样做了. 逻辑上, 让一个语言 省略赋值语句來使得它变得强大也是不可能的, 不论这是多么糟糕的设计的.

甚至一个函数式程序员应该不满意这些优点, 因为这对帮助他们探索函数式语言的能力是没帮助的. 我们不可能写出一个完全缺少赋值语句的程序或者完全引用透明. 这不是衡量一个程序的质量, 因此把目标放在这里是没用的.

明显地, 这种描述函数式编程的特性是不够充分的. 我们必须找到一些不只是解释函数式编程的 威力的东西, 并且我们必须指出函数式编程该努力方向.

和结构化编程的类比

指出函数式编程和结构化编程的对比是十分有帮助的. 在过去, 结构化编程的特性和优点或多或少 被总结如下: 结构化程序没有 goto 语句. 语句块没有更多的入口和出口. 结构化程序比非结构 化结构程序更容易进行数学上的操作 (more tractable mathematically). 我们在早期发现 这些特性和函数式编程有很大的相似性. 这些本质上都是否定的, 从而导致太多没有结果的争论 "goto必不可少"等.

显而易见的是 结构化编程的这些属性虽然有帮助, 但是不能解决问题的核心. 结构化编程和 非结构化编程的最大不同是 结构化程序被设计成模块化. 模块化提高了生产力. 首先, 小模块 能够被快速和容易的编写. 其次, 一般的目标模块能够被重用, 使我们能够更快的产生子程序. 第三, 程序模块能够被独立测试, 帮助花费在调试的时间.

不使用 "goto" 等都是几乎没有作用的, 起到关键作用的是 模块化. 像 Modula-II, Ada, ML(不是make love) 等语言, 都包括提高模块化的功能. 然而, 有一点关键的地方一直被 忽略. 当编写一个模块化程序的时候, 首先要分解问题成子问题, 然后解决子问题并且合并 解决方法. 分解问题的方式直接影响到粘合解决方式. 因此, 观念上提高模块化能力, 必须 在程序语言中提供新的粘合方法. 复杂的作用域规则 和 支持分块编译 仅仅起到一点点的帮助, 他们没有提供新概念上的工具來分解问题.

通过对在工匠上类比, 我们了解到粘合的重要性. 一张椅子通过-坐垫, 脚, 背等并且通过正确的 组合他们之后能被轻易的做成. 但这由木板和插口的连接能力决定. 缺少这个能力, 只能通过 雕刻坚固的木块的來做成. 这十分困难. 这个例子证明了模块化的巨大能力和有正确的黏合剂的 重要性.

现在让我们回到函数式编程. 在剩下的文章里我们将要讨论函数式编程提供给我们的两个新的 非常重要的黏合剂. 我们将会给出许多程序例子來证明函数式编程能用新的方法來模块化, 并且 更简单. 这是函数式编程的关键. 他让我们大大地提供了模块化. 这也是函数式编程的追求目标-- 更小, 更简洁, 更具模块化, 用我们将要描述的新的黏合剂去组合.

为什么函数式编程是重要的 --1