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

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

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

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

它给你的初次印象不友善

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

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

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

新奇事物

一旦你学会了几种语言后,所有的语言都开始看起来都很相似。知道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 datain 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 Haskell 和 Real World Haskell 这两本有用的指导材料。这些书写的非常好,很有价值,而且可以免费在网上找到。如果你想试一下Haskell,这些书可以当作你的寻宝图。

函数式编程很难,这正是你要学习它的原因相关推荐

  1. 为什么很多人都认为编程很难学?

    很多进入计算机专业就读的学生,最初至少有一大半对真实的软件开发完全不了解,是"一张白纸". 不幸的是,学了四年之后,许多张"白纸"又变成了许多罐"浆糊 ...

  2. 大学生学习编程很难吗?怎么样才能学好编程?

    有很多的人是非常的想知道,学编程难吗?编程入门先学什么?往下看希望对你们有起到帮助. 一:学编程难吗? 编程说难不难,说难不难,说简单不简单,学习之前你首先要知道你的学习目标,知道要学来干嘛. 要从事 ...

  3. 《看聊天记录都学不会C语言?太菜了吧》(6)编程很难吗?差一点就学不会了呢!

    若是大一学子或者是真心想学习刚入门的小伙伴可以私聊我,若你是真心学习可以送你书籍,指导你学习,给予你目标方向的学习路线,无套路,博客为证. 本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新 ...

  4. 编程很难?很枯燥?那我们就玩起来燥起来。

    编程很难?很枯燥?那我们就玩起来燥起来. 今天我们继续利用米思齐软件,来玩转物联网开发板,今天我们玩点好玩的又实用的,那就是利用开发板和DH11温湿度模块以及1602A LCD显示屏等材料制作一款高精 ...

  5. (一)少儿编程是什么、编程很难么,怎么学、学什么?

    看看别人怎么说 摘自XX培训机构:随着社会的飞速发展,我们已经快速进入数字化社会.现在孩子从出生的那一刻开始,就注定了和我们大人出生时不同....(此处省略10000字), 青少年编程不仅仅是锻炼孩子 ...

  6. 入行 14 年,我还是觉得编程很难

    很多年前,当我还是一名计算机专业的大四学生时,整天上网浏览各类招聘信息,想找到一个合适的程序员实习岗位. 除了实习岗位外,我偶尔也会点进一些"高级工程师"的招聘帖里.现在回想起那些 ...

  7. 为什么函数式编程很重要:不一样的白板图

    2019独角兽企业重金招聘Python工程师标准>>> 为什么我们要学习函数式编程?为获得更好的软件设计技术! 一天,我们设计了一个流程,来校对款项的收支平衡.下面这张图就是我们在几 ...

  8. 为什么大学感觉学编程很难?原因有这三点。

    为什么很多计算机系的大学生觉得在学校学不好编程? 大学学习还是以理论为主 大学开设的课程还是以主体的理论学习为主,主要是营造一个好的学术氛围,不可能太专注于专业实践,起到抛砖引玉的作用,把基础的理论铺 ...

  9. 震惊!某程序员吐槽零基础自学编程很难,真的是这样吗?

    前言:在自学编程的过程中,一部分程序员遇到冰冷的英语字母,枯燥的编程教程,果断选择了放弃.但其实自学编程不是那么难,只要是逻辑思维或者理科比较好的还行的小伙伴,编程入门完全可以. 零基础程序员自学编程 ...

最新文章

  1. new一个新对象的时候,各属性方法的操行顺序
  2. 鸿蒙2.0 安卓,华为鸿蒙2.0可以替代安卓吗,华为鸿蒙2.0优势在哪
  3. 4.3.6 无分类编址CIDR
  4. Android官方开发文档Training系列课程中文版:管理音频播放之音频输出硬件的处理
  5. python第九十一天----第十六周作业
  6. Android零基础入门第64节:揭开RecyclerView庐山真面目
  7. 数据库改名方法-第三种脚本
  8. linux之抓包神器tcpdump
  9. 提升研发效率 保障数据安全——阿里云宣布数据管理DMS企业版正式商业化 1
  10. CCNA学习指南第三章
  11. R7000刷梅林固件一个小结(变砖解决)
  12. html下拉和收起,Vue中实现菜单下拉、收起的动画效果
  13. java中XML转JSON、JSON转XML、XML转对象(Object)、对象(Object)转XML,利用XSD验证XML(手把手教你如何接收、处理、验证XML数据)
  14. TEXMACS在ubuntu下的使用
  15. 丘成桐:数理与人文(官方完整版PDF下载)(公号回复“丘成桐数学”下载PDF典型资料,欢迎转发、赞赏支持科普)
  16. MySql 新增数据
  17. 学生信息表 成绩表+12章练习
  18. uni-app Image组件在加载图片发生错误时,显示默认图片
  19. ARCore从零到一 (1) 搭建开发环境
  20. 对称加密php,PHP实现对称加密与解密

热门文章

  1. C#接口归纳总结实例详解
  2. 对分查找的最多次数_「剑指offer题解」数组中出现次数超过一半的数字
  3. centos7安装flink集群_《从0到1学习Flink》—— Flink 写入数据到 Kafka
  4. ios开发问题汇总(一)
  5. 数据结构 - 多路搜索树(2-3树、b树、b+树、b*树)
  6. 【JS 逆向百例】某空气质量监测平台无限 debugger 以及数据动态加密分析
  7. 【Python CheckiO 题解】House Password
  8. 【CodeForces - 602D】Lipshitz Sequence(思维,单调栈,斜率单调性)
  9. 3.深度学习练习:Planar data classification with one hidden layer
  10. denison php,Parker / Denison丹尼逊柱塞泵首相系列相关说明