函数式编程思维1.1 范式转变_函数式编程思维1.1 范式转变试读-查字典图书网
查字典图书网
当前位置: 查字典 > 图书网 > 编程 > 函数式编程思维 > 1.1 范式转变

函数式编程思维——1.1 范式转变

我们用几分钟来想象一下自己是一名伐木工人,手里有林场里最好的斧子,因此你是 工作效率最高的。突然有一天场里来了个推销的,他把一种新的砍树工具——链锯——给夸到了天上去。这人很有说服力,所以你也买了一把,不过你不懂得怎么用。你估摸着按照自己原来擅长的砍树方法,把链锯大力地挥向树干——不知道要先发动它。“链锯不过是时髦的样子货罢了”,没砍几下你就得出了这样的结论,于是把它丢到一边重新捡起用惯了的斧子。就在这个时候,有人在你面前把链锯给发动了…… 学习一种全新的编程范式,困难并不在于掌握新的语言。毕竟能拿起这本书的读者, 学过的编程语言少说也有一箩筐——语法不过是些小细节罢了。真正考验人的,是怎么学会用另一种方式去思考。 本书探讨函数式编程的话题,但重点并不放在函数式编程语言上。请别误会,我并不 打算空谈理论,书里会有用很多种语言写成的大量代码,实际上整本书都是围绕着代码来展开的。用“函数式”的方式编写代码牵涉到诸多方面,我会用具体的例子来解说各方面的要旨,包括设计上的种种取舍、不同重用单元的作用等。比起语法,我更看重思路,因此解说会从Java 语言入手,毕竟这是最大的开发者群体的最基本的共同语言,而且会掺杂Java8 和旧版Java 的例子。我会尽可能地用Java 语言(或其近亲)来解释函数式编程概念,仅仅用其他语言来演示一些独有的特性。也许你对Scala 和Clojure 一点都不感兴趣,下半辈子能有现在用着的语言就心满意足了,可是你的语言并不会停下来,反而时刻都在变得更加函数式,也径直带着你一起。所以说,现在快来学学函数式编程范式吧,这样,当有一天(不是假如)函数式降临你日常使用的语言的时候,你才知道如何驾驭它。我们不妨先了解一下,为什么所有的语言都日渐向函数式靠拢。 1.1 范式转变 计算机科学的进步经常是间歇式的,好思路有时搁置数十年后才突然间变成主流。举 个例子,第一种面向对象的语言Simula 67 是1967 年发明的,可是直到1983 年诞生的C++ 终于流行起来以后,面向对象才真正成为主流。很多时候,再优秀的想法也得等待技术基础慢慢成熟。早年Java 总被认为太慢,内存耗费太高,不适合高性能的应用,如今硬件市场的变迁把它变成了极具吸引力的选择。 函数式编程的发展轨迹与面向对象编程十分相似,它也是诞生在学院里,然后用几十 年的时间悄悄浸染了所有的现代编程语言。不过,仅仅在语言里加入一些新语法,并不足以让开发者完全发挥出这种新思维的全部力量。 我们的讨论可以从两种风格的对比开始,尝试分别用传统编程风格(命令式的循环) 和函数式特征更明显的方式来解决同一道题目。这道题目出自计算机科学史上的著名事件,是当年Communications of the ACM 杂志“Programming Pearls”专栏的作者Jon Bentley 向计算机科学先驱Donald Knuth 提出的挑战。涉猎过文本操作的开发者会很熟悉这道题目:读入一个文本文件,确定所有单词的使用频率并从高到低排序,打印出所有单词及其频率的排序列表。对于问题中的词频统计部分,我给出了一个“传统”Java 的解答,见例1-1。 例1-1 首先建立了一个“虚词”(nonwords)的集合(包括冠词和其他起连接作用的 词),然后实现了wordFreq() 方法。方法中首先建立一个Map 结构来容纳由单词和词频组成的键值对,接着构造了一个用来识别单词的正则表达式。接下来的大段篇幅逐一遍历所有找到的单词,将首次遇到的单词添入Map 结构,将重复遇到的单词的出现次数加1。对于提倡以步进方式处理集合(如例中正则表达式的匹配结果)遍历的语言来说,这是司空见惯的编码风格。 Java 8 新增了Stream API 和以lambda 块方式实现的高阶函数(后文将会详细介绍),我们利用这些新的编程手段来改写上面的例子,就得到例1-2。 在例1-2 里,我将正则表达式的匹配结果转换为stream,更方便后续执行互相独立的几项操作:将所有的单词条目转换为小写,滤除虚词,计算余下单词的词频。我把regexToList() 方法经由find() 产生的匹配结果集合转换成stream,这是为了让后续的操作能够像我们考虑问题的方式一样,做完一步再去做下一步。虽然将命令式风格的例1-1改为对集合进行三次循环遍历(第一遍把所有的单词变成小写,第二遍滤除虚词,第三遍计算词频)也能达成目的,但这种写法的效率会惨不忍睹。例1-1 在一个迭代块里完成三项操作,这是牺牲了代码的清晰来换取执行性能。哪怕这种牺牲再稀松平常,我总是不情愿的。 Clojure 语言(http://clojure.org/)的发明人Rich Hickey 在Strange Loop 会议 上做过一堂题为“Simple Made Easy” 的演(http://www.infoq.com/presentations/Simple-Made-Easy),他翻出了一个已经很少用到的老词——“交织”(complect):穿插缠绕地合为一体,使错综复杂。命令式编程风格常常迫使我们出于性能考虑,把不同的任务交织起来,以便能够用一次循环来完成多个任务。而函数式编程用map()、filter() 这些高阶函数把我们解放出来,让我们站在更高的抽象层次上去考虑问题,把问题看得更清楚。后文我们将看到许多函数式思维破解交织现象的例子。

展开全文

推荐文章

猜你喜欢

附近的人在看

推荐阅读

拓展阅读

《函数式编程思维》其他试读目录

• 1.1 范式转变 [当前]
• 1.2 跟上语言发展的潮流
• 1.3 把控制权让渡给语言/运行时
• 1.4 简洁