深入javascript_函数式编程_函子

函子

  • 概念: Functor
  • 容器:包含值和值的特殊关系(这个变形关系就是函数)
  • 函子:是一个特殊的容器 通过一个普通的对象来实现,该对象具有 map 方法 ,map 方法可以运行一个函数对值进行出(变形关系)
  • 函子的作用:处理副作用 异常处理 异步操作等

函子的结构

// 创建一个类 
  class Contains{
 // 构造器
    constructor(value){
         this._value = value
     }
// map方法
     map(fn){
         return new Contains(fn(this._value))
     }
 }

 let r = new Contains(5).map(x=>x+1).map(x=>x*x)
 console.log(r); // 36
  • 总结
    • 函数式编程的运算不直接操作值,而是由函子来做变形处理
    • 函子就是一个实现了map方法的一个容器
    • 可以把函子想象成一个盒子,这个盒子里封装了值,想要处理这个值我么需要给map方法传递一个处理值的函数
    • 永远不会取出值

在Functor中如果我们传入null或undefined

 class Contains{
     constructor(value){
        this._value = value
     }
     map(fn){
         return new Contains(fn(this._value))
     }
 }

 let r = new Contains(5).map(x=>x+1).map(x=>x*x)
 console.log(r); // 36
class Contains{
    static of(val){
        return new Contains(val)
    }
    constructor(value){
        this._value = value
    }
    map(fn){
        return Contains.of(fn(this._value))
    }
}
let r = new Contains(5).map(x=>x+2).map(x=>x*x)
console.log(r); // 49

// 演示 null undefined的问题  如果不小心传入了空值 
Contains.of(null).map(x=>x.toUpperCase())

Maybe函子

对函子内部参数错误如传入null或者undefined进行处理,控制副作用在可控范围内

class MayBe{
    static of(val){
        return new MayBe(val)
    }
    constructor(val){
        this._val = val
    }
    map(fn){
        return this.isNothing()?MayBe.of(null):MayBe.of(fn(this._val))
    }
    isNothing(){
        return this._val === null || this._val === undefined
    }
}

let r = MayBe.of('hello lala').map(x=>x.toUpperCase())
// console.log(r);

let r1 = MayBe.of(null).map(x=>x.toUpperCase())
// console.log(r1);

let r2 = MayBe.of('hello lala')
        .map(x=>x.toUpperCase())
        .map(x=>null)
        .map(x=>x.split(' '))
console.log(r2);

Either函子

异常会让函数变得不纯,Either函子可以用来处理异常 类似 if…else…

class Left{
    static of(val){
        return new Left(val)
    }
    constructor(val){
        this._val = val
    }
    map(fn){
        return this
    }
}

class Right{
    static of(val){
        return new Right(val)
    }
    constructor(val){
        this._val = val
    }
    map(fn){
        return Right.of(fn(this._val))
    }
}

let r1 = Right.of(12).map(x=>x+2)
let r2 = Left.of(12).map(x=>x+2)
console.log(r1);
console.log(r2);

function parseJson(str) {
    try {
        return Right.of(JSON.parse(str))
    } catch (e) {
        return Left.of({err:e.message})
    }
}
let r = parseJson('{"name":"zs"}').map(x=>x.name.toUpperCase())

console.log(r);

IO函子

  • 内部存储的是一个函数,把函数作为值来处理
  • IO函子把不纯的函数存储起来,让不纯的操作交给调用者进行延迟执行,把副作用控制在可控范围
const fp = require('lodash/fp')

class IO{
    static of(val){
        return new IO(function(){
            return val
        })
    }
    constructor(val){
        this._val = val
    }
    map(fn){
        return new IO(fp.flowRight(fn,this._val))
    }
}

let r = IO.of(process).map(p=>p.execPath)

console.log(r);
console.log(r._val());

Task函子

  • 使用folktale中的Task来演示。
  • folktale是一个标准的函数式编程库。
  • 只提供了一些函数式处理操作,如compose、curry等 一些函子Task、Either、MayBe等
const {compose,curry} = require('folktale/core/lambda')
const {toUpper,first} = require('lodash/fp')

let f = curry(2,(x,y)=>x+y)

console.log(f(1,2));
console.log(f(1)(2));

let f1 = compose(toUpper,first)
console.log(f1(['one','two']));

task异步执行

const fs = require('fs')

const { task } = require('folktale/concurrency/task')
const {split,find} = require('lodash/fp')

function readFile(fileName){
    return task(resolver=>{
        fs.readFile(fileName,'utf-8',(err,data)=>{
            if(err) resolver.reject(err)
            resolver.resolve(data)
        })
    })
}

readFile('../../package.json')
.map(split('\n'))
.map(find(x=>x.includes('version')))
.run()
.listen({
    onRejected:err=>{
        console.log(err);
    },
    onResolved:value=>{
        console.log(value);
    }
})

Pointed函子

  • Pointed函子是实现了of静态方法的函子
  • of方法是为了避免使用new来创建对象,更深层的含义是of方法来把值放到上下文Context(把值放到容器中,使用map来处理)
 class Contains{
    static of(val){
        return new Contains(val)
    }
    ...
}
Contains.of(2).map(x=>x+1)

Monad(单子)

  • 一个函子如果具有join和of两个方法并遵守一些定律就是一个Monad
const fs = require('fs')
const fp = require('lodash/fp')

class IO{
    static of(val){
        return new IO(()=>val)
    }
    constructor(val){
        this._val = val
    }
    map(fn){
        return new IO(fp.flowRight(fn,this._val))
    }
}

let readFile = (filename)=>{
    return new IO(()=>fs.readFileSync(filename,'utf-8'))
}
let print = (x)=>{
    return new IO(()=>{
        console.log(x);
        return x
    })
}

let cat = fp.flowRight(print,readFile)
let r = cat('../../package.json')._val()._val()
console.log(r);
const fs = require('fs')
const fp = require('lodash/fp')

class IO{
    static of(val){
        return new IO(()=>val)
    }
    constructor(fn){
        this._val = fn
    }
    map(fn){
        return new IO(fp.flowRight(fn,this._val))
    }
    join(){
        return this._val()
    }
    flatMap(fn){
        return this.map(fn).join()
    }
}

let readFile = (filename)=>{
    return new IO(()=>fs.readFileSync(filename,'utf-8'))
}
let print = (x)=>{
    return new IO(()=>{
        console.log(x);
        return x
    })
}
let r = readFile('../../package.json') 
        .map(fp.toUpper)
        .flatMap(print)
        .join()
    console.log(r);
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页