Applicative 函子

有的时候,我们需要让两个容器产生联系,比如我们想这样:

add(Container.of(2), Container.of(3)); // NaN

这样是行不通的,因为 2 和 3 都藏在瓶子里。

ap 就是这样一种函数,能够把一个 functor 的函数值应用到另一个 functor 的值上。

applicative函子 是实现了 ap 方法的 pointed functor

class Ap {
  constructor(val) {
    this.val = val;
  }
  static of(x) {
    return new Ap(x);
  };
  map(f) {
    return Ap.of(f(this.val));
  }
  ap(F) {
    return Ap.of(this.val(F.val));
  }
}
function add(x) {
  return function (y) {
    return x + y;
  };
}
Ap.of(add).ap(Maybe.of(2)).ap(Maybe.of(3)); // Ap(5)
// or
Ap.of(add(2)).ap(Maybe.of(3));

Ap函子有个特性:

Ap.of(x).map(f) == Ap.of(f).ap(Ap.of(x))

比如:

Ap.of(x => x + 2).ap(Functor.of(2)) // Ap(4)
Ap.of(2).map(x => x + 2) // Ap(4)

并行执行

假设我们要创建一个旅游网站,既需要获取游客目的地的列表,还需要获取地方事件的列表。这两个请求就是相互独立的 api 调用。

var renderPage = _.curry(function(destinations, events) { /* render page */  });
Task.of(renderPage).ap(Http.get('/destinations')).ap(Http.get('/events'))

两个请求将会同时立即执行,当两者的响应都返回之后,renderPage 就会被调用。这与 monad 版本的那种必须等待前一个任务完成才能继续执行后面的操作完全不同。本来我们就无需根据目的地来获取事件,因此也就不需要依赖顺序执行。

需要强调,因为我们是使用局部调用的函数来达成上述结果的,所以必须要保证 renderpage 是 curry 函数,否则它就不会一直等到两个 Task 都完成。

lift

我们可以以一种 pointfree 的方式调用 applicative functor。因为 map 等价于 of/ap,那么我们就可以定义无数个能够 ap 通用函数。

var liftA1 = _.curry(function(f, functor1) {
  return functor1.map(f);
});
var liftA2 = _.curry(function(f, functor1, functor2) {
  return functor1.map(f).ap(functor2);
});
var liftA3 = _.curry(function(f, functor1, functor2, functor3) {
  return functor1.map(f).ap(functor2).ap(functor3);
});
// liftA4, etc
liftA1(add(3), Ap.of(2)) // Ap(5)
liftA2(add, Ap.of(6), Ap.of(2)) // Ap(8)

衍生

由于 of/ap 等价于 map,那么我们就可以利用这点来定义 map:

// 从 of/ap 衍生出的 map
X.prototype.map = function(f) {
  return this.constructor.of(f).ap(this);
}

monad 可以说是处在食物链的顶端,因此如果已经有了一个 chain 函数,那么就可以免费得到 functor 和 applicative:

// 从 chain 衍生出的 map
X.prototype.map = function(f) {
  var m = this;
  return m.chain(function(a) {
    return m.constructor.of(f(a));
  });
}
// 从 chain/map 衍生出的 ap
X.prototype.ap = function(other) {
  return this.chain(function(f) {
    return other.map(f);
  });
};

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress