准备充分了嘛就想学函数式编程?(Part 6)

本文讲的是准备充分了嘛就想学函数式编程?(Part 6),


第一步,理解函数式编程概念是最重要的一步,同时也是最难的一步。如果你从正确的角度或方法来理解的话,它也未必会有那么难。

回顾之前的部分: Part 1Part 2Part 3Part 4Part 5

现在该做什么?

现在你已经学会了所有这些新东西了,你可能在想,“现在该干什么?我如何在日常编程中使用它?”

这得看情况。如果你会使用纯函数式语言(如 Elm 或 Haskell)编程,那么你可以尝试所有这些想法。这些语言能够很容易实现这些想法。

如果你只会使用 Javascript 这样的命令式语言编程(我们中大多数人肯定都是),那么你仍然可以使用很多你学到的知识,但是还需要更多的训练。

Javascript 函数式

Javascript 有许多特性能让你以近乎函数式的方式编程。它不是纯粹的函数式,但你可以从语言中得到不变性,甚至更多的库。

它不是最佳的,但如果你必须使用的时候,那为什么不利用一些函数式语言的优点呢?

不变性

首先要考虑的是不变性。 在 ES2015,或者也叫 ES6,因为它有一个被称为 常量 的新关键字。这意味着一旦设置了变量,则无法修改该变量:

const a = 1;
a = 2; // this will throw a TypeError in Chrome, Firefox or Node
       // but not in Safari (circa 10/2016)

这里的 a 被定义为常量,意味着一旦赋值无法再改变。 这就是为什么 a = 2 会抛出异常 (除了 Safari)。

Javascript 常量 有个问题就是不变性不够深入。以下示例说明了其限制:

const a = {
    x: 1,
    y: 2
};
a.x = 2; // NO EXCEPTION!
a = {}; // this will throw a TypeError

注意 a.x = 2 并没有抛出异常。 const 关键字的不变性只对变量 a 生效。 a 所指向的任何变量都可以改变。

这是非常令人失望的,因为它本可以让 Javascript 更好。

那么我们如何从 Javascript 中获得不变性呢?

很不幸,我们只能通过一个库 Immutable.js 来实现。 这可能给我们更好的不变性,但可悲的是,它实现的方式使我们的代码看起来更像 Java。

柯里化和组合

在本系列之前的文章,我们学习了如何编写柯里化的功能。这是一个更复杂的例子:

const f = a => b => c => d => a + b + c + d

请注意,我们不得不手工编写柯里化部分。

调用 f, 我们必须写成:

console.log(f(1)(2)(3)(4)); // prints 10

但是这么多的括号,足以让 Lisp 程序员哭泣了!(译者注:Lisp 语句中会使用很多括号)

有许多库能够简化这一过程。 我最喜欢的一个是 Ramda.

使用 Ramda 我们可以这样写:

const f = R.curry((a, b, c, d) => a + b + c + d);
console.log(f(1, 2, 3, 4)); // 打印 10
console.log(f(1, 2)(3, 4)); // 也打印 10
console.log(f(1)(2)(3, 4)); // 也打印 10

函数定义并没有什么改进,但我们已经消除了对所有括号的需求。请注意,我们可以应用与我们每次调用 f 时一样多的参数。

通过 Ramda, 我们可以重写 Part 3和 Part 4 mult5AfterAdd10 功能:

const add = R.curry((x, y) => x + y);
const mult5 = value => value * 5;
const mult5AfterAdd10 = R.compose(mult5, add(10));

事实证明,Ramda 有很多帮助函数来做这些事情,例如。R.add 和 R.multiply,这意味着我们可以少写代码:

const mult5AfterAdd10 = R.compose(R.multiply(5), R.add(10));

Map, Filter 和 Reduce

Ramda 也有它自己的 mapfilter 和 reduce。 尽管这些功能在普通 Javascript Array.prototype 中已经存在, Ramda 的版本功能更加丰富:

const isOdd = R.flip(R.modulo)(2);
const onlyOdd = R.filter(isOdd);
const isEven = R.complement(isOdd);
const onlyEven = R.filter(isEven);

const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(onlyEven(numbers)); // prints [2, 4, 6, 8]
console.log(onlyOdd(numbers)); // prints [1, 3, 5, 7]

R.modulo 用了两个参数. 第一个是 dividend (被除数) ,第二个参数是 divisor (除数)。

isOdd 函数只是除以 2 的余数。余数为 0 是 falsy, 不是奇数,余数为 1 则是 truthy,奇数。 我们翻转 modulo 的第一和第二参数,使得我们可以指定 2 作为除数。

isEven 功能只是 isOdd 的 complement(补集)

onlyOdd 函数是通过 isOdd 来 断言(只返回布尔类型的方法) 的 过滤器 。它在等待 numbers 数组,即它在执行前需要的的最后一个参数。

The onlyEven 是一个使用 isEven 来断言的 过滤器 。

当我们将 numbers 传给 onlyEven 、onlyOdd 、isEven 和 isOdd 方法,获取它们最终的参数,最后执行然后返回我们期望的结果。

Javascript 缺点

Javascript 已经有很多的库,语言也得到增强,它仍然需要面对残酷的现实,它是一种命令式语言,对大家来说似乎能够做任何事情。

大多数前端人员在浏览器中一直使用着 Javascript ,因为一直以来只有这一种选择。但现在许多开发人员逐渐不再直接编写 Javascript。

取而代之,他们用不同的语言编写和编译,或者更准确的说,是用其他语言转换成 Javascript。

CoffeeScript 就是这些语言中的第一种。如今,Angular 2 中采用了 Typescript。Babel 也是一种 Javascript 转换编译器。

越来越多的人正在采用这种方法用于生产环境。

但是这些语言还是基于 Javascript ,而且只是稍微改进了一点点。为什么不从一个纯函数式语言转换到 Javascript?

Elm

在这个系列里,我们了解了 Elm 来帮助理解函数式编程。

但是什么才是 Elm?我又该怎么用它呢?

Elm 是一种纯函数式编程语言,最终编译成 Javascript ,所以你可以用它来创建 Web 应用,使用 The Elm Architecture,又叫 TEA(这个架构激励了 Redux 的开发者)。

Elm 程序没有任何运行时错误。

像 NoRedInk 这样的公司已经在生产环境中使用了 Elm,Elm 的创造者 Evan Czapliki 现在工作的公司(他之前在 Prezi 公司工作)。

看看这个访谈,6 个月应用 Elm 在生产环境, 由来自 NoRedInk 的 Richard Feldman 和 Elm 的布道者讲解。

我需要用 Elm 替换我所有的 Javascript 吗?

不,你可以逐渐替换。 完整的看看这篇文章 How to use Elm at Work,来学习更多知识。

为什么学习 Elm?

  1. 函数式编程是限制和自由并存的。它限制了你可以做什么(大部分是保证你不会“误伤”自己),但是同时也让你远离 bug 和错误的设计决策,因为所有的 Elm 程序遵循 Elm Architecture,一个函数式响应编程模型。
  2. 函数式编程能让你成为一个更好的程序员。本文中的想法只是冰山一角。 你真的需要在实践中看到,它们是如何让你的程序缩小尺寸,增加稳定性。
  3. Javascript 最初是在 10 天内构建的,然后在过去的二十年中修补,以成为一种有点功能,有点面向对象和完全命令式的编程语言。 Elm 的设计吸取了 Haskell 社区过去 30 年工作中的知识,以及数十年的数学和计算机科学经验。 Elm 架构(TEA)是经过多年设计和完善的,是 Evan 在功能响应式性编程中论文的结果。看看 Controlling Time and Space(控制时间和空间),以了解这个设计的构思。
  4. Elm 专为前端 Web 开发人员而设计。 它的目的是使他们的工作更容易。 观看 Let’s Be Mainstream(让我们成为主流),更好地了解这一目标。

未来

不可能知道将来会怎样,但我们可以做一些猜测。下面是一些我的:

将会出现一个明确的语言,编译为 Javascript。

已经存在了 40 多年的函数式编程思想将被重新发现,以解决当前的软件复杂性问题。

硬件的状态,例如千兆字节的便宜内存和快速处理器,将使函数式技术成为可行。

CPU 不会变得更快,但内核的数量将继续增加。

可变状态将成为复杂系统中的最大问题之一。

我写这系列文章,因为我相信未来是函数式编程的未来,在过去的几年中,我在努力学习它(我还在学习)。

我的目标就是帮助别人比我更容易和更快的去学习这些概念,帮助别人成为更好的程序员,以便他们将来能有更好的就业前景。

即使我的预测,Elm 在未来将是一门伟大的语言是错误的,我可以肯定地说,函数式编程和 Elm 也会在未来的画卷上留下浓墨重彩的一笔。

我希望在阅读完本系列以后,你会对你的能力和这些概念的理解感到更加自信。

在今后的工作中,祝你好运。





原文发布时间为:2016年11月17日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2025-01-27 15:45:39

准备充分了嘛就想学函数式编程?(Part 6)的相关文章

准备充分了嘛就想学函数式编程?(第一部分)

本文讲的是准备充分了嘛就想学函数式编程?(第一部分), 迈出理解函数式编程概念的第一步是最重要的,有时也是最难的一步.但是不一定特别难.只要选对了思考方法就不难. 学开车 第一次学车时,我们也曾挣扎过.看别人学开车时觉得真的很简单.但事实上学车比我们想象的难多了. 我们借父母的车子练习,在家周围街道上开熟练之前甚至都不敢冒险开到公路上去. 但是通过不断的练习,在经历过一些父母想忘掉的担心令人的经历之后,我们学会了开车,最终拿到了驾照. 拿到驾照之后我们一有机会就会把车开出去.每次出行都会让我们的

准备充分了嘛就想学函数式编程?(第五部分)

本文讲的是准备充分了嘛就想学函数式编程?(第五部分), 迈出理解函数式编程概念的第一步是最重要的,有时也是最难的一步.但是不一定特别难.只要选对了思考方法就不难. 前几部分: 第一部分, 第二部分, 第三部分, 第四部分 引用透明 引用透明 是一个很酷炫的术语,它指的是一个纯函数能够安全地被它的表达式所替代.下面用一个例子来解释这个术语. 在代数中当你有以下这个公式时: y = x + 10 并且已知: x = 3 你可以将 x 代入方程来得到: y = 3 + 10 此时这个方程依旧成立.我们

准备充分了嘛就想学函数式编程?(第四部分)

本文讲的是准备充分了嘛就想学函数式编程?(第四部分), 想要理解函数式编程,第一步总是最重要,也是最困难的.但是只要有了正确的思维,其实也不是太难. 之前的部分: 第一部分, 第二部分, 第三部分 柯里化 如果你还记得第三部分内容的话,就会知道我们在组合 mult5 和 add 这两个函数时遇到问题的原因是:mult5 接收一个参数而 add 却接收两个. 其实只需要通过限制所有函数都只接收一个参数,就可以轻易地解决这个问题. 相信我,这并没有听起来那么糟糕. 我们只需要来写一个使用两个参数,但

准备充分了嘛就想学函数式编程?(Part 2)

本文讲的是准备充分了嘛就想学函数式编程?(Part 2), 想要理解函数式编程,第一步总是最重要,也是最困难的.但是只要有了正确的思维,其实也不是太难. 之前的部分: 第一部分 友情提示 请读仔细读代码,确保继续之前你已经理解.每一代码段落都基于它之前的代码. 如果你太急,可能会遗漏一些重要的细节. 重构 让我们先来重构一段 JavaScript 代码: function validateSsn(ssn) { if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn)) consol

想学jsp web编程,各位大虾有好意见么

问题描述 想学jspweb编程,各位大虾有好意见么 解决方案 解决方案二:多动手敲代码,多做项目解决方案三:做两个jsp+servlet+JavaBean的网站.熟悉mvc框架的结构.看下jsp,servlet相关书籍,struts,spring,hibernate相关书籍解决方案四:从jspservletjdbc整起解决方案五:我是学java方面的,jspweb我觉得是需要发一点时间的,现在学的话都是关于SSH编程的.建议下点视频看看.解决方案六:LZ基础是主要...先抓起基础.然后在学习框架

《JavaScript函数式编程》读后感_javascript技巧

本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习. 在近期看到了<JavaScript函数式编程>这本书预售的时候就定了下来.主要目的是个人目前还是不理解什么是函数式编程.在自己学习的过程中一直听到身边的人说面向过程编程和面向对象编程,而函数式就非常少.为了自己不要落后于其他同学的脚步,故想以写笔记的方式去分享和记录自己阅读中所汲取的知识. js 和函数式编程 书中用了一句简单的话来回答了什么是函数式编程: 函数式编程通过使用函数来将值转换为抽象单元

我想学计算机-想学计算机!从根本学起

问题描述 想学计算机!从根本学起 谁知道有什么书介绍了计算机的起源及发展和原理,还有汇编语言,c语言的原理 解决方案 要想学计算机,关键是要有一个系统的过程.大家都知道,计算机是美国人发明的,所以要学计算机需要看原版的高质量的书籍.看了不对的书,就要走冤枉路.像楼下的书,难度就比较大,不适合lz.姐姐有一些很好的入门的书,介绍各种原理的.都是金针度人的好书.lz如果采纳了姐姐的回答(方法是点击姐姐回答右边的采纳按钮),姐姐发给你.祝你好运. 解决方案二: 要想学计算机,关键是要系统的学习.1.硬

学做界面#-想学做界面的信息安全专业的会敲代码的色影丝小学渣

问题描述 想学做界面的信息安全专业的会敲代码的色影丝小学渣 自身具备的艺术素养对做出优质的界面有助推作用吗?我对别人做的界面的构图位置美观吧啦吧啦很敏感,脑中会形成一个自己感觉更舒服的界面版式,这对做出优质的界面有助推作用吗,还是小学生胡思乱想了,第一次提问,求指示,轻喷. 解决方案 有艺术细胞是好事.但是如果过于强调这个,而忽略了系统的学习.理性和理论,那么是没什么好处的. 一个靠直觉和自发得到的经验而进行界面设计的人,可能你能设计用户群体和你本人有着相同背景的简单的小软件. 但是一个前端交互

jsp-下边的代码谁懂啊,大神求解释。顺道告诉我下想学关于这个看什么,谢谢啦

问题描述 下边的代码谁懂啊,大神求解释.顺道告诉我下想学关于这个看什么,谢谢啦 <head> <jsp:include page='/res/inc/inc.jsp' flush='true'/> <style> .FixedTitleRow { position: relative; top: expression( this.offsetParent.scrollTop ); z-index: 10; background-color: #ffffff; } .Fi