函子举例

114 阅读2分钟

  • MayBe函子:处理空值的异常 --内部的value是保存一个值
  • Either函子:对异常进行处理 --内部的value是保存一个值
  • IO函子:延期执行一个函数,可以控制副作用 --内部的value是保存一个函数
  • Task函子:对异步进行处理
  • Pointed函子:实现了of静态方法的函子
  • Monad函子: 解决函子嵌套的问题,同时有静态的of方法,也有join方法,就是Monad函子
  1. MayBe函子
// MayBe 函子
class MayBe {
  static of (value) {
    return new MayBe(value)
  }

  constructor (value) {
    this._value = value
  }

  map (fn) {
    return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))
  }

  isNothing () {
    return this._value === null || this._value === undefined
  }
}


// let r = MayBe.of('Hello World')
//           .map(x => x.toUpperCase())
// console.log(r)


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


let r = MayBe.of('hello world')
          .map(x => x.toUpperCase())
          .map(x => null)
          .map(x => x.split(' '))
console.log(r)
  1. Either函子
    • Either两者中的任何一个,类似于if....else....的处理
    • 异常会让函数变的不纯,Either函子可以用来做异常处理
// 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))
  }
}

// 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({ error: e.message })
  }
}

// let r = parseJSON('{ name: zs }')
// console.log(r)

let r = parseJSON('{ "name": "zs" }')
          .map(x => x.name.toUpperCase())
console.log(r)
  1. IO(input output 输入 输出)函子
    • IO函子中的_value是一个函数,这里是把函数作为值来处理
    • IO函子可以把不纯的动作存储到_value中,延迟执行这个不纯的操作(惰性执行),包装当前的操作(纯函数)
    • 把不纯的操作,交给调用者来处理
// IO 函子
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))
  }
}

// 调用
let r = IO.of(process).map(p => p.execPath)
// console.log(r)
console.log(r._value())

IO函子的问题:嵌套函子不方便,monad函子可解决

// IO 函子的问题
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))
  }
}

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 cat = fp.flowRight(print, readFile)
// IO(IO(x))
let r = cat('package.json')._value()._value()
console.log(r)
  1. 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)
    }
  })
  1. Pointed函子

    • 实现了of静态方法的函子
    • of方法是为了避免使用new来创建对象,更深层的含义是of方法用来把值放到上下文context(把值放到容器中,使用map来处理值)
  2. Monad函子

    • 是可以变扁的Pointed函子,IO(IO(x))
    • 一个函子如果有join和of两个方法并遵守一些定律就是一个Monad函子
// IO Monad
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.json')
          // .map(x => x.toUpperCase())
          .map(fp.toUpper)
          .flatMap(print)
          .join()

console.log(r)