关于函数式编程的思考

Posted 前端深夜告解室

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于函数式编程的思考相关的知识,希望对你有一定的参考价值。

题外话:只是单纯地谈谈个人对函数式编程的理解,欢迎大家来一起探讨。也不会提及高阶函数与范畴学的内容,只聊一些很入门的问题。函数式编程的优点这里也不做过多说明,会推荐大家看几篇文章,里面有很好的阐述。

斜体灰字部分是一些个人的吐槽和私货

目录

  1. 为什么函数式编程在前端复兴?

  2. 什么是函数式编程?

  3. 函数式编程如何思考问题?

  4. 函数式编程与面向对象编程有什么区别,各自的优缺点是什么?

  5. map,reduce是函数式编程吗?

  6. 推荐

    书接上文

4.用这道很简单的应用题,我们来尝试对比一下函数式编程与面向对象编程的区别。

其实这个应用题给了大家一些暗示,让大家不知不觉走到了“陷阱”中

  • 标明这是应用题,引导大家用数学的思维去思考

  • 给出的已知条件,进一步引导大家用四则运算去思考

把这两个暗示去掉,我们再来看一下这个问题 :

小雨带着n个苹果出去玩,路过薛大叔家,薛大叔给了她n个苹果,薛大婶给了她1个苹果。路过张砖头家,小雨给了张砖头n个苹果小雨现在有多少个苹果?

用面向对象的思维该如何解决这个问题?

  1. 第一步 抽象个类

  2. 第二步 添加属性和方法

class Person {
constructor(name, apples) {
this.name = name;
this.apples = apples;
}

receive(num) {
this.apples += num;
}

give(num) {
this.apples -= num;
}

getApples() {
console.log(this.apples);
}
}

let n = 10;
let xiaoYu = new Person('小雨', n);
xiaoYu.receive(n);// 薛大叔给了n个
xiaoYu.receive(1);// 薛大婶给了n个
xiaoYu.give(n);// 给了张砖头n个
let result = xiaoYu.getApples();// 答案

对比一下刚刚函数式思维的代码:

let n = 10;
// 加法
function add(x, y) {
return x + y;
}
// 减法
function sub(x, y) {
return x - y;
}
let result = add(n, 1);// 答案

首先说说函数式思维代码的优点:

  • 代码更加简洁,行数更少

  • 执行更加高效

  • 测试更加简单。

如果我们要测试送苹果这个动作,只需要测试sub这个函数。但是对于面向对象思维的代码,我们需要new一个对象,初始化name与apples,运行give方法,验证getApples得到的结果是否正确。

看一个吐槽:“面向对象编程语言的问题在于,它总是附带着所有它需要的隐含环境。你想要一个香蕉,但得到的却是一个大猩猩拿着香蕉,而其还有整个丛林。” — Joe Armstrong(Erlang语言发明人)

再说一说函数式思维代码的缺点:

  • 直接给了结果add(n, 1),如果不知道你的推导过程,根本不知道你究竟在搞什么。

  • 如果不写出你的思路,完全不知道这个题目跟add与sub函数有什么关系。

从以上分析的优缺点,我们可以初步理解为什么函数式编程会很高效。但是同时也要清楚,函数式编程要比面向对象编程更加需要注释,要清楚地描述是如何将实际问题抽象成数学问题的,推导过程是怎样的。通过对比也可以看出来,面向对象的代码相对容易理解,而容易理解是非常重要的优势,因为我们常说:要写出人能理解的代码。

如果上面的应用题的一个条件改为“路过张砖头家,小雨给了张砖头5个苹果”两种思维方式的改动成本也是不一样的。对于面向对象思维,需要找到描述这个动作的代码,进行修改;对于函数式思维可能需要重新推导相关流程。

面向对象的思维在努力地告诉我们:说出你的世界,我们用代码描述它函数式的思维在冷冰冰地跟我们说:说出你的世界,我们把它转换成数学

这个例子应该会引起很多人的疑惑,这是一道应用题,简单用了个加减乘除,跟函数式编程没有什么关系啊。其实我自己也很苦恼啊,该怎么把这个事情圆回来啊

如果大家认可这道题用加减法去做才是最正常的思维,那恭喜你已经有了函数式的思维,大家已经很自然地把题目中小明收到苹果抽象成了加法,小明给出去苹果抽象成了减法。你们已经做到了第一步——把实际问题抽象为数学问题 :)再吹一波我朝的基础教育。这是一个应付98元,给收银员103元,秒找5元的国度。
四则运算尽管没有那么高大上,但是还真可以跟函数式编程扯上点儿关系。运算符号+和运算符号-是可以当成函数看待的,运算符号的两边的数字看做函数输入,结果看做函数输出。如果感兴趣,可以看一下Haskell中对四则运算符的使用,相信看过之后大家会有更加直观的感受。

5.最后,map、reduce是不是函数式编程?

这是一个好问题,也是一个很有意思的问题,确实有很多函数式编程的文章在讲解并且强调这些函数的用法。我想用另一个问题来解释一下这个问题:类是不是面向对象编程?很多人会告诉我,类是面向对象编程中一个很重要的概念,但是不应该仅仅用有没有类来区分是不是面向对象的思维,即使用了类,如果不理解面向对象的思维,依旧会写出很多不是面向对象的代码。我觉得同样可以解释一下map和reduce:这是函数式编程中比较常用的函数,但是如果你不理解函数式编程的思维,依旧可以用map和reduce写出很多非函数式的代码。

6.推荐

里面有一本讲haskell的书,这种为函数式而生的语言,个人觉得大家可以了解一下。简单看看Haskell语言的设计,会让大家有一些收获。看到Haskell的函数天生柯里化,可能会让你感到这个语言的神奇,同时也可以思考一下js的柯里化看到 (+3) 可以作为一个函数使用的时候,可能会让你感到这个世界的神奇

看看名人大家是如何吐槽面向对象的

(http://www.vaikan.com/object-oriented-programming-is-inherently-harmful/)


傻瓜函数式编程

(https://github.com/justinyhuang/Functional-Programming-For-The-Rest-of-Us-Cn/blob/master/FunctionalProgrammingForTheRestOfUs.cn.md)


JS函数式编程指南

(https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/)


HASKELL 趣学指南

(https://learnyoua.haskell.sg/content/zh-cn/)


Functor, Applicative, 以及 Monad 的图片阐释

(http://jiyinyiyong.github.io/monads-in-pictures/)



简历请投递至邮箱

FSP.FE@meituan.com


关于函数式编程的思考(2)

新美大智能支付终端团队


面向互联网开发从业者;

我们将分享团队技术文章,提供研发岗位招聘信息等。


以上是关于关于函数式编程的思考的主要内容,如果未能解决你的问题,请参考以下文章

不仅仅是装逼——函数式的意义

面向过程,面向对象,函数式对同一个问题的思考方式

前端必学——函数式编程

函数式编程

关于this指向思考

AKKA-HTTP DSL源码解读