JS函数式编程03--函子

2020-06-12  本文已影响0人  小q

函子

函子的概念

函子是函数式编程里面最重要的数据类型,也是基本的运算单位和功能单位。
函子首先是一个容器,它包含了值和值的变形关系,这个变形关系就是函数。
函子可以把函数式编程副作用控制在可控的范围内,包括处理异常,异步操作等。
一般约定,函子的标志就是容器具有map方法。该方法将容器里面的每一个值,映射到另一个容器。

函子的基本构造

函子就是一个特殊的容器,它可以由对象来实现,这个对象中包含了值,这个值永远不会对外公布,有一个map方法,用来操作这个值。还有一个of方法,用来生成一个新的容器。

class Functor {
  static of(value){
    return new Functor(value)
  }

  constructor(val){
    this._value = val
  }

  map(fn){
    return Functor.of(fn(this._value ))
  }
}

//使用的时候
const func = Functor.of.map(x => x+1)
func(1)//Container { _value: 2 }

这里总结一下函子的使用

MayBe函子

函子会接收各种函数来处理内部的值,这里就有可能遇到错误,我们需要对这些错误做处理,MayBe函子的作用就是对外部的空值情况做处理。

MayBe函子的构造就是在map中设置空值检查

  class Maybe{
    static of(value){
      return new Maybe(value)
    }

    constructor(val){
      this._value = val
    }
    map(f) {
      return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
    }
  }

虽然 MayBe函子可以避免出现错误,但是多次调用map时我们并不知道哪里出现了错误

Either函子

Either函子与if...else处理很相似。它内部有两个值,左值和右值。右值通常代表正常的值,左值是当右值不存在或错误时的默认值

  class Either {
     static of(left,right){
      return new Either (left,right))
    }
    constructor(left,right){
      this.left = left
      this.right = right
    }
    map(fn){
      return this.right ? Either.of(this.left,fn(this.right)) : Either.of(fn(this.left),right)
    }
  }

此外,Either函子另一个用途是替代try...catch,使用左值来表示错误

  function parseJSON(json) {
  try {
    return Either.of(null, JSON.parse(json));
  } catch (e: Error) {
    return Either.of(e, null);
  }
}

ap函子

函子中的值有可能是数值,也有可能是一个函数,我们想让值为函数的函子用另一个函子中的值运算,我们就可以用ap函子

  function add(x) {
    return x + 1
  }
  const A = Functor.of(2)
  const B = Functor.of(add)

  class Ap extends Functor {
    ap(F) {
      return Ap.of(this.val(F.val))
    }
  }

   //我们想让B函子的值使用A函子的值
  Ap.of(add).ap(Functor.of(2))

凡是部署了ap方法的函子,就是ap函子。ap函子的意义在于对多参数的函数,可以从多个容器中取值,实现函子的链式调用。

Monad 函子

函子中的值可以接受任何值,所以函子之中可以包含另一个函子。这样就会造成函子多层嵌套的问题。取值时会很不方便。Monad函子的作用就是:总是返回一个单层的函子,它有一个FlatMap方法,与map方法作用相同,唯一的区别就是如果生成了一个嵌套函子,它会取出后者的值,保证返回的永远是一个单层的容器,不会出现嵌套的情况。

  class Monad extends Functor {
    join() {
      return this.val;
    }
    flatMap(f) {//f是一个函子
      return this.map(f).join();
    }
  }

如果函数f返回的是一个函子,那么this.map(f)就会生成一个嵌套的函子。所以,join方法保证了flatMap方法总是返回一个单层的函子。这意味着嵌套的函子会被铺平。

IO函子

I/O是一个不纯的操作,普通的函数式编程无法处理,所以使用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));
    }
}

参考

函数式编程入门教程

上一篇 下一篇

猜你喜欢

热点阅读