摘要:函数式编程逐渐被边缘化,被抛弃到学术界和非主流的场外。组合式编程的重新崛起年左右,有个巨大的变化爆发了。人们开始逐渐在私下里谈论函数式编程。箭头函数对于函数式编程的爆发起到了推动剂的作用。现在很少看到那种不用函数式编程的大型应用了。
本文作者: Eric Elliott
编译:胡子大哈翻译原文:http://huziketang.com/blog/posts/detail?postId=58e3062ba58c240ae35bb8de
英文连接:The Rise and Fall and Rise of Functional Programming (Composing Software)
转载请注明出处,保留原文链接以及作者信息
本文是“组合式软件”系列的一篇文章,从头开始学习函数式编程和使用 JavaScript ES6+ 进行软件编程。请继续关注,后面还有很多相关内容。
在我 6 岁的时候,我每天花很多时间和我最好的朋友一起打游戏,他们家里有很多电脑。对我来讲它有种魔幻版不可抗拒的力量。有一天我突然问我朋友:“我们怎样才能自己做一个游戏呢?”
他也不知道,所以我们一起去问他的爸爸,叔叔从很高的架子上拿下来一本书:Basic。我也由此开始了我的编程之旅。后来大学都有代数这门课程,而我对它已经很熟悉了,因为编程里面代数是基础,到处都是代数。
组合式软件的兴起在计算机科学刚刚起步的时候,很多计算机科学的理论都还没有落地。那时候有两个伟大的计算机科学家:阿隆佐·丘奇和阿兰·图灵。他们创造了两个不同的,但是具有同等效力的通用计算模型。两个模型都可以计算任何可以计算的东西(着重强调,“通用”)。
阿隆佐·丘奇发明了 λ 演算, λ 演算是基于函数应用的通用计算模型。阿兰·图灵则因图灵机而广为人知。图灵机定义了一个理论上的设备,它可以控制条带上的符号。他们合作证明了 λ 演算和图灵机是功能等价的。
λ 演算全部都是关于函数组合。函数组合在软件开发中是非常富有表现力和说服力的。本文中,我们会讨论函数组合在软件设计中的重要性。
这里有三点关于 λ 演算的特殊说明:
函数通常是匿名的。在 JavaScript 中,const sum = (x, y) => x + y 的右边是匿名函数,即 (x, y) => x + y。
λ 演算中的函数只接受单一输入,它是一元的。如果你需要传递多参数,函数会接受第一个输入并且返回一个新的函数来接受第二个参数,以此类推。一个 n 元函数 (x, y) => x + y 可以表达为一个一元函数:x => y => x + y。这种 n 元函数到一元函数的转化叫做柯里化。
函数是一级的。意思是说一个函数可以作为另一个函数的输入,并且一个函数可以返回另一个函数。
这些特征一起构成了简单且容易理解的规则,在组合式软件中使用函数作为主要编码单元。在 JavaScript 中,匿名函数和柯里化函数都是可选特征,也就是说 JavaScript 支持 λ 演算的主要特征但是并不强制使用。
经典的函数组合是把一个函数的输出作为另一个函数的输入,例如下面的组合:
f·g
可以写成:
compose2 = f => g => x => f(g(x))
下面是如何使用它:
double = n => n * 2 inc = n => n + 1 compose2(double)(inc)(3)
compose2() 函数接受 double 函数作为第一个参数,inc 函数作为第二个参数,最后应用参数 3 到这两个函数组合上。再看一下 compose2() 的声明,f 是 double(),g 是 inc(),x 是 3。函数调用 compose2(double)(inc)(3),实际上是三个不同的函数调用:
首先传递 double 返回一个新函数 1;
新函数 1 以 inc 为参数并且返回一个新函数 2;
新函数 2 以 3 为参数并且计算 f(g(x)),即 double(inc(3));
x=3 传递给 inc();
inc(3) 计算结果是 4;
double(4) 计算结果是 8;
最终返回结果是 8。
组合式软件的过程可以用函数组合图来表达,看下面代码:
append = s1 => s2 => s1 + s2 append("Hello, ")("world!")
可以用图来模拟表示:
λ 演算对软件设计的影响是深远的,直到大约 1980 年,计算机科学界很多有影响力的品牌,都是采用函数组合的方式来开发自己的软件。Lisp 是 1958 年发明的,它深受 λ 演算的影响。直到今天,Lisp 是依旧广为使用的第二大历史悠久的语言。
我是通过 AutoLISP 知道的 Lisp,AutoLISP 是在最流行的电脑辅助设计(CAD)软件——AutoCAD,中使用的脚本语言。AutoCAD 太流行了,使得其他所有的 CAD 应用几乎都支持 AutoLISP 以保持其兼容性。Lisp 依然能够在计算机科学课程中广为使用有三个主要原因:
Lisp 非常简单,基本上可以在一天之内学习完它的基本语法和语义;
Lisp 基本上全部是函数组合,函数组合来做应用架构的方式非常优雅;
我所知道的最好的计算机科学课本使用Lisp:计算机程序的结构和解释
组合式软件的没落在 1970 到 1980 年期间,软件开发的方式开始发生变化,简单的组合式开发不再受宠。出现了面向对象编程,它基于组件封装和信息传递的思想,在当时是非常先进的。代码通过继承来实现复用,继承关系是一种叫做 is-a 的关系。
函数式编程逐渐被边缘化,被抛弃到学术界和非主流的场外。在 1990 — 2010 年期间对三种人形成了甜蜜的困扰,一种是编程极客,一种是大学教授,一种是逃离了 Java 思想强制灌输的幸运的学生。而对于我们来讲,这 30 年的软件开发有一点噩梦般的感觉,黑暗的年代。
组合式编程的重新崛起2010 年左右,有个巨大的变化:JavaScript 爆发了。在 2006 年以前,JavaScript 一直被认为是一种玩具式的编程语言,可以在浏览器中做一些很可爱的动画,但是在这背后隐藏着潜力巨大的特点,即 λ 演算的重要特征。人们开始逐渐在私下里谈论“函数式编程”。
到 2015 年,用函数组合来开发软件重新开始流行起来。为了简化使用,JavaScript 规范也做了 10 年以来的首次重大升级,增加了箭头函数。箭头函数使创建和使用函数、柯里化和 λ 演算变得很容易。
箭头函数对于 JavaScript 函数式编程的爆发起到了推动剂的作用。现在很少看到那种不用函数式编程的大型应用了。
组合的方式可以简洁清晰地描述软件的行为,把一些小的、确定性的函数组合成大的组件,进而形成软件,这样的软件很容易组织、理解、调试、扩展、测试和维护。
在读接下来文章的时候,希望你能通过例子自己动手做实验。回想一下当自己还是的孩子的时候,把一些东西拆开,自己再学着组装、拼接。重新找回童年探索事物的感觉,希望你能享受这个过程。
如果本文对你有帮助,欢迎关注我的专栏-前端大哈,定期发布高质量前端文章。
我最近正在写一本《React.js 小书》,对 React.js 感兴趣的童鞋,欢迎指点。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/82455.html
摘要:强化学习这就是神经网络流行起来的地方。而且,我们也在这一范围内取得了强化学习史上最重要的成绩之一一个学习并成为西洋双陆棋玩家的神经网络。递归神经网络图。 这是「神经网络和深度学习简史」的第三部分(第一部分,第二部分)。在这一部分,我们将继续了解90年代研究的飞速发展,搞清楚神经网络在60年代末失去众多青睐的原因。神经网络做决定神经网络运用于无监督学习的发现之旅结束后,让我们也快速了解一下它们...
摘要:作者宋天龙来源科技大本营导语一切都始于年的那个圣诞节,的诞生并不算恰逢其时,它崛起充满了机遇巧合,也有其必然性。年的圣诞节,开始编写语言的编译器。年发布的标志着的框架基本确定。年月发布了系列的最后一个版本,主版本号为。 showImg(https://segmentfault.com/img/remote/1460000019862276); 作者 | 宋天龙来源 | AI科技大本营 ...
摘要:模块化编程,已经成为一个迫切的需求。但是,不是一种模块化编程语言,它不支持类,更遑论模块了。本文总结了当前模块化编程的最佳实践,说明如何投入实用。就是模块的基本写法。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。 随着WEB的快速崛起,网页越来越像桌面程序,需要一个团队分工协作、进度管理、单元测试等等......开发者不得不使用软件工程的方法,管理网页的业务逻辑。 Ja...
摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。背后的故事本文是对于年之间世界发生的大事件的详细介绍,阐述了从提出到角力到流产的前世今生。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎...
摘要:前端日报精选刘海打理指北中的错误处理模式与反模式译图解和译你并不知道中文装饰器让你的代码更简洁众成翻译第期每个程序员第一份工作前应该知道的件事中的不变性众成翻译写的一次小结掘金内部机制探秘和文末附彩蛋和源码前端杂谈开发实战 2017-09-30 前端日报 精选 iPhone X 刘海打理指北React16中的错误处理ES6 Promise:模式与反模式「译」图解 ArrayBuffer...
阅读 2727·2021-09-24 09:47
阅读 4367·2021-08-27 13:10
阅读 2983·2019-08-30 15:44
阅读 1284·2019-08-29 12:56
阅读 2595·2019-08-28 18:07
阅读 2616·2019-08-26 14:05
阅读 2557·2019-08-26 13:41
阅读 1267·2019-08-26 13:33