函数式编程学习总结
什么是函数式编程?
函数编程是一种编程风格。把过程抽象成函数,让数据在纯函数间流动。
纯函数
纯函数的意思是函数内部不接受任何外界的影响,相同的参数得到的输出总是相同。
纯函数的好处
可缓存性
纯函数总是根据输入来确定输出的值,这样就可把一些需要重复使用的输入缓存下来。
利于测试
因为纯函数不依赖外界,在测试时就不用准备运行时环境,只需要根据输入断言输出。
函数柯里化
概念:
只传递给函数的一部分参数来调用它,返回一个函数来处理剩余的参数。
柯里化的好处:
尽可能的函数化。通过传递部分参数的形式得到一个新的函数。这样像是对部分参数做了一个缓存。
function add(x){
return function(y){
return x + y;
}
}
let addOne = add(1);
addOne(2);
组合(compose)
组合就是像管道一样把不同的函数联系起来,数据在其中流动。
好处:
组合的代码更有可读性。如f(g(h(x)))这样的嵌套函数,把这种嵌套过程进行封装。
就需要写compose(f,g,h)这样的代码。
容器
容器有两样东西:值,函数。容器的作用就是把外界隔开,只能通过指定的接口才能操作。
函子(functor)
定义:functor是实现了map函数并遵守一些特定规则的容器类型。
就是说函子的标志就是容器具有map方法,map将容器里的所有值映射到另一个容器。
函子就是函数式编程的基本单位,运算不同,衍生了不同类型的函子。
Function (value){
this.value = valuse;
}
Function.prototype.map = function(f){
return new Function(f(this.value);
}
Maybe函子
Maybe函子用于处理空值检查。它的map方法的实现就是:
Maybe.prototype.map = function(f){
return this.value ? Maybe.of(null):Maybe.of(f(this.value);
}
Either函子
Either函子就是处理try-catch和if-else 这样的问题。
有Left和right两个子类。使来Left表示错误和不为真的情况。
Left.prototype.map = function(x){
return this;
}
Right.prototype.map = function(f){
return Right.of(f(this.value);
}
//Left 和Right的区别在于,Left的map方法只是返回这个容器,不做任何事情。这样就可以用Left来传递错误消息。
Left可以让调用链中任意一环的错误立刻返回到调用链的尾部,这给我们错误处理带来了很大的方便,再也不用一层又一层的 try/catch。
Monad函子
Monad函子就是用来处理函子嵌套。它的作用就是返回一个单层的函子。
函子是一个容器,它的值可以是任意类型。也就是说函子的值可以是另一个函子。
当函子出现嵌套时,就需要使用this.value().this.value()方式来取值,这时就是需要Monad函子。
其内部实现:
Monad.prototype.join(){
return this.value;
}
用join方法去掉外壳,保证返回的是一个单层的函子。
Monad.protype.chain(f){
return this.map(f).join();
}
ap函子
ap就是这样一种函数,能够把一functor的函数值应用到另一个 functor 的值上。
function addTwo(x) {
return x + 2;
}
const A = Functor.of(2);
const B = Ap.of(addTwo)
Ap.ap = function (otherFunctor){
return Ap.of(this.value(otherFunctor.value)
}
Ap.of(addTwo).ap(Functor.of(2))
IO
var getFromStorage = function(key) {
return function() {
return localStorage[key];
}
}