跳到主要内容

函子

什么是函子 (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来处理值)

Monad 函子