函数式编程很难,这正是你要学的缘由

很奇怪不是,不多有人天天都使用函数式编程语言。 若是你用Scala,Haskell,Erlang,F#或某个Lisp方言来编程,极可能没有公司会花钱聘你。这个行业里的绝大部分人都是使用像 Python,Ruby,Java或C#等面向对象的编程语言——它们用起来很顺手。不错,你也许会偶然用到一两个“函数式语言特征”,例如 “block”,但人们不会去作函数式编程。 html

然而,不少年来,咱们一直被教导说函数式编程语言很好很棒。我仍然记得当我第一次阅读ESR的著名的关于学习Lisp语言的论文时的困惑。也许大多数的人对Paul Graham 的《Beating The Averages》这篇文章更加熟悉: 程序员

使用Lisp开发使咱们的开发周期迭代的如此之快,以致于有时当竞争对手在新闻发布会上推出他们的新功能一两天后,咱们就能复制出一样的功能。当报道产品发布的新闻记者打电话给咱们时,咱们的产品已经拥有了一样的功能特征。 算法

那些皈依函数式编程的人中,一直常见的考虑是:学习这种新的、函数式的语言“对你有好处”;就像是某些人建议说天天30分钟的健身房活动会“让你的 身体健康”同样。但这也同时暗示了这样作的难度和须要的付出。Lisp语言跟Haskell、Ocaml和Scala语言不一样,被认为是出了名的难学,可 以说是臭名昭著。文雅的人说这是Lisp语言的“深度&广度”的体现。不文雅的人说这是“意淫”或“玩弄学术”或简单的“不必”。我认为,它的 难度跟你对它熟不熟悉有关,并且,这种难度是一种重要指标显示:学习这样的一种语言会让你编程更有效率、能力更强。 编程

它给你的初次印象不友善 数据结构

我7岁时就开始编程,在漫长无聊的郊区夏季里,在我祖父的计算机上瞎搞一气。我学了BASIC,用它在屏幕上画一个蹦跳的球。我学了Pascal, 用它写了一个能经过PC喇叭放音乐的程序。大概10岁时我学了C语言,但遇到了一堵越不过去的墙,直到我上了高中。那就是:指针。即便不算这些该死的指 针,我写、读、学习、练习中,一样遭遇无数的失败。我把祖父的硬盘给毁掉了两次(一次属意外),最后弄得很多次要本身重装操做系统。我失败,一遍遍的失 败。 架构

也许你也有跟我类似的故事,也许是彻底不一样的一个。但我想,差很少全部学过编程的人都有过遇到困难的经历。咱们在学了一些基本知识后,必然会遇到一些公认的概念上的关口,好比“指针”。不少计算机科学教授会把指针描述为他们课程上的过滤网。若是你想成为一名优秀的程序员,你必需要能理解指针。不多人能轻松的掌握它们。大多数人,包括我,则须要不断的练习和参考例子来理解什么是指针、为何它们很重要。 app

这种艰难的努力过程不是偶然的,是一种几乎广泛的现象。指针是一种很是强大和基础功能的概念。学会它能让你成为一名更好的程序员,能让你的思考更加形象化。即便你使用的语言并不提供指针这样的特征,但跟指针相似的数据结构和概念却随处可见。 编程语言

新奇事物 分布式

一旦你学会了几种语言后,全部的语言都开始看起来都很类似。知道Python的人学习Ruby可能不会遇到太多的问题,知道Java的人学习C#会 感到很熟悉。不错,也有意外的地方。Ruby爱好者在学习Python时会对它的comprehension感到吃惊,Java用户会对C#里的委派摸不着头脑。仍是那句话,若是你只瞟一眼,它们都很类似。我能够打保票的说,若是你还未曾有过这样的认识,一旦你学了一种Lisp语言,你会发现全部的Lisp变种都很类似。 函数式编程

有人说,大部分人第一次使用Haskell或Ocaml时都彻底的不知所措。见鬼了,在Haskell里,连分号都跟别人不同。这并非语法的问题;Haskell和ML语言彻底基于一种不一样的概念、一种新的语言范式。你须要用不一样的方式开发应用,不一样的方式组织应用,不一样的方式扩展应用。

不少这样的新概念都具备难以想象的强大力量。Haskell里的Monads 是跟指针同样基础且强大的概念(你极可能在不知道它叫什么的状况下就已经使用过它们了)。因此,跟学了Java后再学C#不同,有志向学习函数式语言的 人须要往回走的更远,去学习更加基础的概念后才能接下去学习。就像是彻底再学习一次指针。而且,就像是当年咱们刚开始学习编程同样,一些很大的概念看起来 会让人迷惑茫然,让人沮丧,直到你去攻克(以及失败)它们。

吃下你的药丸,找到你的药剂师

尽管很差学,但我坚信,学习这些函数式编程语言会在职业上对你有好处。我相信有些人读到这点时会眼睛翻起来向天看,很难想象出这些monoids 或 monad 会对他们在使用Java或C#时有用处。对我而言,我已经不惊奇于因为这样的思惟而阻止他们学习函数式语言的现象;他们须要学习一种跟指针和递归同样基础 的新概念。他们须要有一种只有专业人员在完成清晰的商业目标时才具备的耐心和斗志。不多人能在过了可塑的年龄后还受得了挫折——一次又一次的挫折——不然 咱们如今都早成专家了,不是吗?

还有更复杂的东西,有大量的语言和算法研究都是用函数式语言实施的(尤为是Haskell)。你很容易会被这些不熟悉的概念——例如分类学理论half-finished abstractions,一些失败的研究——弄的迷失方向。没有一个清晰的指导(好比由一个实用主义的做者写的一本好书),原本已经很困难的学习任务变的更加可怕。
这些叠加起来的复杂因素致使了不出意外的结果:不少人不情愿在函数式编程学习中投入时间。很容易理解这种不情愿,“我干吗不把花在学习这些东西的时间用在 实现什么东西上呢?”但这种思路也代表了你永远不肯意在任何新技术上浪费时间(只用本身熟悉的)。在一个像软件技术这样突飞猛进的产业里,我不认为这是正 确的判断。

眼见为实

学习一种函数式编程语言最显而易见的好处是,你能学会这种类型语言中的函数式概念。它能帮助你的大脑,让它具备能很是清晰的思考和处理一些惊人的重 大概念的能力。这并非函数式编程具备魔法;各类语言和范式的出现都是为了应对某一特定类别的问题。函数式编程的杀手锏正是应对了当今世界上日益增加的并 行性编程和元数据编程趋势。

例如,咱们研究一个简化的、本地版本化的Google著名的MapReduce范例。用函数式方式描述这种范例是难以想象的清晰简洁:

mapReducer data partitioner mapper reducer =                let partitions = partitioner data                in reduce reducer (map mapper partitions)

让这样的代码支持并行计算或分布式并行计算是垂手可得的(对于本地并行计算,不少的功能包都支持“pmap”和“preduce“——只须要利用函 数式语言的一些简单特性)。像maps, partitions, generators, streams, reductions, folds, 已以及 function chaining等概念在各类的函数式编程语言中都大同小异,因此,任何对Lisp,Haskell,OCaml,甚至带点函数式语言特征的语言—— Python和Ruby熟悉的人,都会很容易的理解这里面的思想精华。

让咱们花点时间考虑一下,如何用一种面向对象的语言,以一种常见的面向对象的模式来清楚的描述这种架构。至少你须要作的事情是定义用来描述 mapper和reducer的声明。若是你有好奇心,请试着用你喜欢的面向对象语言描述一个最小化的“面向对象”的MapReduce。我发现那是很是 罗嗦的。若是使用Java风格的语言,它会像这样:

interface Mapper {   B map(A input); }

 interface Reducer {   Y reduce(X a, X b); }

 abstract class MapReduce {   private Mapper mapper;   private Reducer reducer;

   public MapReduce(Mapper map, Reducer reduce) {     // ...   }

   public run(SeqenceType data) {     // ...   } }

即便是没有加入循环逻辑,这种缺少函数式模式中常见的名词和动词的使用,使得MapReduce这种技术很难被定义。这种定义方式几乎是滑稽好笑的,但它能让你想到函数式概念。另一个好例子是Scala语言如何利用完备的Java Fork/Join 类库,把它轻松的集成的本身的自有语法中

各有所求

因此,我鼓励任何想进步的程序员:请考虑学习一种函数式语言。Haskell和OCaml都是极好的选择,F#和Erlang也至关的不错。它们都 很差学,但也许这是个好事。努力弄清楚你遇到的复杂的概念,看看是否有其余人正在利用这些概念;常常的,你会在寻找这些不熟悉的概念的真正用意的时候实现 思想上的突破。

当你开始学的时候,请注意,不要过于在乎。就像其余任何须要你花时间和精力的事情同样,过分的在函数式编程上进行精力上的投资是很危险的。掉进了认知能力的陷阱后你的投资会血本无归。你很容易会忘掉世界上还有无数种计算模型,你更容易忘掉有多少种优秀的软件根本没有使用任何的函数式概念。
学习的道路会愈来愈难走,但从另外一方面说,在你平常的编程中,你会发现有愈来愈多的可使用的重要概念和模型。对于这样紧凑的编程风格你会愈来愈适应,必然,你也会对如何成为一名更好的软件工程师有了新的认识。

补充

有很多校对这篇文章的人在看完文章后都问了我一个一样的问题:“听起来不错,大卫,但是我应该学习那种语言呢?”固然,这是他们给我出的难题。

我想,若是你是一个颇有经验的程序员,这最能“应付”这个问题的答案是:“选一种符合你的需求的”。若是你须要在JVM上工做,选择Scala或 Clojure。若是你想能快速的开发大型分布式软件系统,选择Erlang。若是你想要一种具备超强编译器的超能干活的语言,请选择Haskell或 RCaml。若是你想要一种比Ruby或Python更有能力的原型工具,选择Scheme。

请记住,咱们在这里要作的这些目的是为了实际的技能和自我进步。若是你能腾出时间学这些,就走出你的安逸环境,挑战本身。

由于我已经学习了Lisp和Erlang,并且使用OCaml作专业工做,我决定研究一下Haskell,这彻底是另一个世界。我发现惟一能帮助我参透这种语言的途径是依赖Learn You A HaskellReal World Haskell 这两本有用的指导材料。这些书写的很是好,颇有价值,并且能够免费在网上找到。若是你想试一下Haskell,这些书能够看成你的寻宝图。

相关文章
相关标签/搜索