JS函数式编程概念理解:函子(Functor)

2,422 阅读5分钟

标签(空格分隔): 函数式编程 函子 functor


很多前端在学习函数式编程之前,都会被各种概念折磨的死去活来,本文的重点算是函数式编程之前的一个甜品,重点在如何切入。

函子即Functor是FP(函数式编程简写)当中重要的概念,理解这个概念对你学习FP后面的很重要。不然学的就是云里雾里。

网上的文章不在少数,很多人也看过,笔者非科班出身,仅从个人角度学习和科普这个知识点

送给川普的猪头肉

有这么一个场景,可以想象下,我们和邻居之间交换东西,都很直接,不需要繁琐的包装等等。就像加减法一样,1 + 1 = 2;假如我要给在美国的亲戚特朗普寄送一些猪头肉。很显然我不能拿着猪头肉直接去。

我首先会把猪头肉包装,那么他就是被容器化之后的肉,交给快递员,我会告诉快递员这个装有肉的容器打开方法,因为通过海关的时候需要打开进行检疫,然后盖上邮戳,重新包装,送往美国白宫。

以上例子并不是肉自己直接走过去的,而是容器化之后的肉,有包装的方法,比如易碎、保险、向上打开等等注意事项,防止海关检查的时候不小心损坏。

我们有用代码实现下

//肉盒子
class MeatBox {
    constructor(meat) {
        this.value = meat;
    }
    //map为打开包装的方法
    map(fn) {
        return new MeatBox(fn(this.meat));
    }
}

海关打开之后检疫完成,他又会根据盒子的规范重新打包成新的肉容器,方便在美国海关检疫。同样美国海关觉得猪头肉和好吃,咬一口,又打包成原来的样子,给川普总统。

继续看代码流程

//把肉容器化
let meatBox1 = new MeatBox('猪头肉');
//海关检疫
let meatBox2 = meatBox.map(function(meat){
    return check(meat);
});
//美国海关咬了一口
let meatBox3 = meatBox.map(function(meat){
    return eat(meat);
});
//川普吃到了你的猪头肉
meatBox3.map(function(meat){
    return Trump(meat);
});

用链式写法

new MeatBox('猪头肉').map(check).map(eat).map(function(trump);

如果白宫在你家隔壁,你直接送过去就行,没这么多事。但是很明显不行。我们总结一下上面几个特点

  • 肉从一个单体或者一个值被容器化了,变成了一个具有数据类型的容器
  • 每一次对肉的都会拿出来进行计算然后又重新根据规则或者协议标准容器化;
  • 容器具有map这个方法,来取值,并且返回的也有map方法;
  • 还可以链式调用;
  • 像我们学习数据时候的映射 y = f(x),包含了值和变形关系;

什么是函子呢(Functor)?

根据以上的场景,得出

  • Functor(函子)遵守一些特定规则的容器类型或者数据编程协议;
  • 具有一个通用的map方法,返回新实例,这个实例和之前实例有相同的规则;
  • 具有结合外部的运算能力;

按照我的理解,函子Functor其实准确的来说是:值被容器化之后具有一条标准协议规范的数据类型或者数据容器。map属于函子的一个特征,Monad(单子),这个概念后面讲,肯定还有跟多的单子。

如果单纯的说具有map的数据类型是函子,没错但是不严谨。比如引用类型数据,很多文章也认为是函子,因为也具有map方法。

其实在阮一峰的文章当中说的很清楚,我就不再阐述,有兴趣的可以看看。

Functor 是一个对于函数调用的抽象,赋予容器自己去调用函数的能力。把东西装进一个容器,只留出一个接口 map 给容器外的函数,map 一个函数时,我们让容器自己来运行这个函数,这样容器就可以自由地选择何时何地如何操作这个函数,以致于拥有惰性求值、错误处理、异步调用等等非常牛掰的特性。

说了这么多,应用场景呢?

其实从上面的场景看,你可能会说,我直接去白宫不就完了,省的川普说为什么有人送了一块咬过得的肉。

在编程开发中,尤其是多人协作,一个数据从数据库出来,会各种计算、加入业务逻辑,最终呈现给消费方。数据链路越长,数据元信息越容易丢失。就好像一句话通过几个人之后,完全和原来的意思相差甚远。

以上只是一方面,更多是融合在函数式编程当中,让数据的计算和业务剥离,我们不用大量的业务逻辑和命令式编程,例如for循环,把重点放在副作用上的等(副作用在这里是中性词);数据链路会更容易清晰去实现。

这就是函子的基本概念,其实也没那么复杂,理解这个对你函数式编程有很大的帮助。

有兴趣的可以关注笔者QQ群:126274877