函子是一个特殊的容器,通过一个普通的对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理,这个值永远不对外开放
在函数式编程中如何把副作用控制在可控的范围内,异常处理,异步操作等
// Point函子是实现了of静态方法的函子
// 含义:of方法用来把值放到上下文Context中用map处理
static of(value) {//不用使用new来创建对象
return new Container(value)
}
constructor(value){//不对外开放
this._value = value
}
map (fn) {//在map中处理value
// return new Container(fn(this._value))
return this.isNothing() ? Container.of(null) : Container.of(fn(this._value))
}
isNothing (){
return this._value === null || this._value === undefined
}
}
let r = new Container(5).map(v => v + 1)
.map(v => v * v)
let rr = Container.of(5).map( v => v + 2)
.map( v => v * v )
let err = Container.of(null).map( v => v.split(' '))
console.log(err)//返回Container对象 -新的函子对象
// 异常
// let err = Container.of(null).map( x => x.split(' ') )
二、maybe函子
作用是可以对外部的空值情况做处理(控制副作用在允许的范围)
constructor(value){
this._value = value
}
static of (value){
return new MayBe(value)
}
map(fn){
return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))
}
isNothing (){
return this._value === null || this._value === undefined
}
}
let mb = MayBe.of('hello').map( v => v.toUpperCase())
let err = MayBe.of(null).map( v => v.toUpperCase())
console.log(err)
let nu = MayBe.of('nnn').map( x => x.toUpperCase())
.map( x => null)
.map( x => x.split(' '))
/
maybe函子可以处理异常 但比如 null 执行中 不知道错误出现在哪里了
三、Either函子
可以用来异常处理 可以记录出错的信息 类似于if...else..
constructor(value){
this._value = value
}
static of(value){
return new Left(value)
}
map(fn){
return this
}
}
class Right{
constructor(value){
this._value = value
}
static of(value){
return new Right(value)
}
map(fn){
return Right.of(fn(this._value))
}
}
// let r1 = Right.of(2).map( x => x + 2) //2
// let r2 = Left.of(2).map( x => x + 2)//4
function parseJSON (str){
try{
return Right.of(JSON.parse(str))
} catch(e){
return Left.of({err : e.message})
}
}
let r = parseJSON('{name: a}')//错误写法
console.log(r)
四、IO函子
IO函子中的_value始终是一个函数,把函数当作值来处理
IO函子可以把不纯的动作存储到_value中共,延迟执行这个不纯的操作(惰性执行),保证当前的操作使纯的,把不纯的操作交给调用者来处理
class IO {
static of(value){//of Point函子(实现了of静态方法的函子)
return new IO(function () {return value})
}
constructor(fn){
this._value = fn //包装的函数
// this._value->function(){return process}
}
map(fn){//当前函子中的value(函数)和传入的fn组合
return new IO(fp.flowRight(fn, this._value))
}
}
let r = IO.of(process).map(p => p.execPath)
console.log(r._value())//r是纯的 不纯的可能存在于r调用过程中
五、Monad函子
解决函子嵌套问题
具有静态的IO和join方法的函子
const fs = require('fs')
const fp = require('lodash/fp')
class IO {
static of(value){
return new IO(function(){
return value
})
}
constructor(fn){
this._value = fn
}
map(fn){
return new IO(fp.flowRight(fn, this._value))
}
join(){
return this._value()
}
flatMap(fn){
return this.map(fn).join()
}
}
let readFile =function(filename){
return new IO(function(){
return fs.readFileSync(filename, 'utf-8')
})
}
let print = function(x){
return new IO(function () {
console.log(x)
return x
})
}
let r = readFile('../package-lock.json')
.map(x = x.toUpperCase())//fp.toUpper
.flatMap(print)
.join()
六、Task函子
处理异步任务
const { split, find } = require('lodash/fp')//柯里化以后的函数
const fs = require('fs')
function readFile(filename){
return task(resolver => {
fs.readFile(filename, 'utf-8', (err, data) => {
if(err) resolver.reject(err)
resolver.resolve(data)
})
})
}
readFile('../package.json')//返回一个Task函子
.map(split('\n'))
.map(find(x => x.includes('version')))
.run()//开始去读取文件
.listen({//监听事件状态
onRejected: err => {
console.log(err)
},
onResolved: value => {
console.log(value)
}
})