函子
什么是函子 (Functor)
容器: 包含值和值的变形关系(这个变形关系就是函数)
函子: 是一个特殊的容器,通过一个普通对象来实现,该对象具有 map
方法,map
方法可以运行一个函数对值进行处理。
总而言之 函数式编程的运算不直接操作值,而是由函子来完成。而函子就是实现了map
的契约对象,我们可以把函子想象成一个盒子,这个盒子封装了一个值,想要处理盒子中的值,我们需要给盒子的map
方法传递一个处理值的函数(纯函数),由这个函数来对值进行处理,最终 map
方法返回一个包含新值的函子盒子
。
函子 (Functor) 的作用
函子
可以把副作用控制在可控的范围内、异常处理、异步操作等。
各类函子作用以及实现
Functor 函子
基础写法
class Container {
constructor(value){
this._value = value;
}
map(fn){
return new Container(fn(this._value));
}
}
const c = new Container(5).map(x=>x+1).map(x=>x*x);
console.log(c);
进阶写法
class Container {
static of (value){
return new Container(value);
}
constructor(value){
this._value = value;
}
map(fn){
return Container.of(fn(this._value));
}
}
const c = Container.of(5).map(x=>x+1).map(x=>x*x);
console.log(c);
MayBe 函子
我们在编程可能会遇到很多错误,需要对这些错误进行相应的处理。MayBe
函子的作用就是可以对外部的空值情况做处理。(控制副作用在允许的范围内)
class MayBe {
static of(value){
return new MayBe(value);
}
constructor(value){
this._value = value;
}
isNothing(){
return this._value === null || this._value === undefined;
}
map(fn){
return this.isNothing()?MayBe.of(null):MayBe.of(fn(this._value));
}
}
const maybe = MayBe.of(null).map(x=>x+4).map(x=>x*4);
console.log(maybe);
Either 函子
Either
两者中的任何一个,类似于if……else……
的处理。异常会让函数变得不纯,Either
函子可以用来异常处理。
class Left{
static of(value){
return new Left(value);
}
constructor(value){
this._value = value;
}
map(fn){
return this;
}
}
class Right{
static of(value){
return new Right(value);
}
constructor(value){
this._value = value;
}
map(fn){
return Right.of(fn(this._value));
}
}
function parseJSON(str){
try{
return Right.of(JSON.parse(str)).map(x=>x.name+'修改');;
}catch(e){
return Left.of({error:e.message});
}
}
// let json = parseJSON('{name:柏拉文}');
// console.log(json);
let json = parseJSON('{"name":"柏拉文"}');
console.log(json);
IO 函子
IO
函子中的_value
是一个函数,我们把函数作为值来处理。IO
函子可以把不纯的动作存储到_value
中,延迟执行这个不纯的动作(惰性执行),包装当前的操作为纯操作,把不纯的操作交给调用者来处理。
function compose(...args){
return function(value){
return args.reverse().reduce((prev,curr)=>{
return curr(prev);
},value);
}
}
class IO{
static of(value){
return new IO(function(){
return value;
});
}
constructor(fn){
this._value = fn;
}
map(fn){
return new IO(compose(fn,this._value));
}
}
const result = IO.of(process).map(p=>p.execPath);
console.log(result._value());
Task 函子
用于处理异步任务
const fs = require('fs');
const {task} = require('folktale/concurrency/task');
function curry(fn){
return function curried(...args){
if(args.length < fn.length){
return function(){
return curried(...args.concat(Array.from(arguments)));
}
}
return fn(...args);
}
}
function split(reg,value){
return value.split(reg);
}
function find(fn,value){
return fn(value);
}
const currySplit = curry(split);
const curryFind = curry(find);
function readFile(filename){
return task(resolver=>{
fs.readFile(filename,'utf-8',(error,data)=>{
if(error){
resolver.reject(error);
}
resolver.resolve(data);
});
});
}
readFile('package.json').map(currySplit('\r')).map(curryFind(x=>x.includes('version'))).run().listen({
onRejected:error=>{
console.log(error);
},
onResolved:value=>{
console.log(value);
}
});
Pointed 函子
Pointed
函子实现了of
静态方法的函子。of
方法是为了避免使用new
来创建对象,更深层的含义是of
方法用来把值放到上下文Context
(把值放到容器中,使用map
来处理值)