函数式编程-函子

什么是函子Functor

容器:包含值和值的变形关系,这个变形关系就是函数
函子:一个特殊的容器,通过一个普通对象实现,该对象具有map方法,map方法可以运行一个函数对值进行处理。

所有的函子都有 map 对象

maybe 函子

优点:对外部空值做处理

缺点:只可以处理空值,但当处理多个 map 的时候,无法定位哪个 map 出现了空值

// 可能会是空值
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;
  }
}

const res = Maybe.of("hello world")
  .map((a) => a.toUpperCase())
  .map((b) => null)
  .map((c) => c.split(" "));

console.log(res); //Maybe { _value: null }

Either 函子

两者中任何一个,类似于 if。。else。。

异常会让函数变得不纯,用 Either 可以进行异常处理

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));
  }
}

function parseJSON(str) {
  try {
    return Right.of(JSON.parse(str));
  } catch (e) {
    return Left.of({ error: e.message });
  }
}

const str = '{name:"hello"}';
const r = parseJSON(str); // Left { _val: { error: 'Unexpected token n in JSON at position 1' } }

const str2 = '{"name":"hello"}';
const r2 = parseJSON(str2).map((item) => item.name.toUpperCase()); // Right { _val: 'HELLO' }

IO 函子

_value 是一个函数,这里把函数作为值来处理

可以把不纯的动作存储到_value 中,延迟执行这个不纯的操作(惰性执行)

把不纯的操作交给调用者处理。

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));
  }
}

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

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

把不纯的操作延迟到调用的时候

folktale task 函子

folktale 与 lodash ramda 不同的是,只提供了函数式处理的操作,如:compose、curry 等,和其他的一些函子,如 Task、Either、Maybe 等

const { compose, curry } = require("folktale/core/lambda");
const { toUpper, first } = require("lodash/fp");

const f = curry(2, (x, y) => x + y); // 第一个参数:参数个数

console.log(f(1)(3)); // 4
console.log(f(1)()(3)); // 4

const f1 = compose(toUpper, first);
console.log(f1(["aaa", "bbb"]));

monad 函子

monad 函子是解决函子嵌套的问题,如:IO(IO(x))

一个函子如果具有 join 和 of 两个方法并遵守一些定律就是一个 monad