函数式编程并不是万金油:大家对我的另外一个常见误解是我推崇纯函数式语言。我的确有理由喜欢它们。看到上面那个式子了吗? c = a + b 如果我想把expr1和expr2的值相加该如何表达呢? c = (expr1) + (expr2) 如果expr1有附加操作而且会影响expr2的值又该如何表达呢?这并不罕见: c = (a++) + (a + b); 这里的问题不是你想的那样。我知道你在想什么:“天知道这门语言会如何解释这个式子。万一计算的顺序反了怎么办?” 你想错了。正是由于人们会产生那样的想法,编程语言才会有这样的特点。要解答你的疑问很简单,看看编译手册就知道了。 上面式子的根本问题是我无法知道那样的计算顺序是偶然的还是有意的。我确切地知道上面式子的会做什么,但我无法确定的是,它的计算顺序是不是有意 的?我能不能优化那个式子,放到一个循环里去?我能不能在多核多线程的情况下调用它?假设有人问我,如果给z赋值10而不是20,会不会影响c的值,我无 法回答。 理论上是无法回答上面那个问题的。当然了我们可以根据经验做加一些断言(assertion)。在断言出了一堆或者一个警告后,理性地说,我们仍然不知道z会不会影响a或者b,最终影响到c。 为什么这很重要代码的可维护性是建立在代码的可阅读性的基础上的。你知道为什么CSS不好吗?如果仅仅是程序员写错了或者设计者把字体和布局规则混淆了,地球人都知道那还不算太坏。CSS坏就坏在如果不加上大量的注释,人们就无法通过字面上的意思来理解代码的意图。 别忘了基于规则的声明式语言并不是新概念,更不是革命。50年前Prolog就提供了类似CSS的声明方式。今天的Erlang也提供了这类方式,并在业界得到广泛应用。 请看下面这行代码: div .title #subtitle {color: blue} 如果不加载试一下的话,我敢打赌你完全想不到这会对页面产生怎样的效果。字面上完全看不出跟其它规则的关系,也看不出它如何处理匹配冲突。 因此对于汝等Ruby/Python/Node.js程序员而言,我的建议是,如果你真想超凡脱俗的话,学学谷歌和Facebook。他们使用一些 实验性技术,并不是为了取代for-loops,而是用来表明for-loops的意图。快速原型的话选择简单的语言就可以了,当需要准确描述意图的时候 才考虑更换编程语言。 命令式语言的必要性:最后,我想解释一下为什么命令式语言是必要的。看看下面这个驱动程序例子: setlpt1(00000000b);setlpt1(00010000b);setlpt1(00000000b); 这是我假想的串口命令协议。这几行代码是按照先后顺序排列的。哪怕200年以后,它们的意图也不会发生什么变化。必要的时候使用命令型语言,明确地 告诉读者不要打乱这些代码。你不应该改变它们的顺序。你也不会把他们用在某些抽象的端口上,它们只适用于串口或者所谓打印机口。 用函数式语言来实现上面的功能,并且加上同步原语来保证它们按照顺序运行,是愚蠢的。 结论:如果说这篇文章有一点点值得总结的东西的话,那便是:下次你写任何代码/规范/程序的时候,问问自己,意图是否清楚表达?未来的维护者看到你写的东西,是否能明白它 本文是在程序师网首次发表。 |