Monad In Javascript

1,094 阅读2分钟

Monad不就是个自函子范畴上的幺半群,这有什么难理解的(A monad is just a monoid in the category of endofunctors) —— Phillip Wadler

自函子(Endofunctor)

什么是自函数(Endofunction) ?
identify :: Number -> Number
自函数就是把类型映射到自身类型。

那什么是自函子?

f: cube :: Number -> (Number,String)
F: cube :: (Number,String) -> (Number,String)
 
f -> F的映射就是自函子。函子有别于函数,函数描述的是类型之间的映射,而函子描述的是范畴之间的映射。那什么是范畴?简单的理解:不同类型的函数组成的集合。那么自函子就是将范畴映射到自身范畴。这里我们找出一个bind 函子实现f -> F的映射。
f :: Number -> (Number,String) => F :: (Number,String) -> (Number,String)

var bind = function(f) {
  return function F(tuple) {
    var x  = tuple[0],
        s  = tuple[1],
        fx = f(x),
        y  = fx[0],
        t  = fx[1];

    return [y, s + t];
  };
};

幺半群

幺半群是一个带有二元运算 *: M × M → M 的集合 M ,其符合下列公理: 结合律:对任何在 M 内的a、b、c, (ab)c = a(bc) 。 单位元:存在一在 M 内的元素e,使得任一于 M 内的 a 都会符合 ae = ea = a 。

我们来实现自函子上的结合律:

var compose = function(f, g) {
  return function(x) {
    return f(g(x));
  };
};

var cube = function(x) {
  return [x * x * x, 'cube was called.'];
};

var sine = function(x) {
  return [Math.sin(x), 'sine was called.'];
};

var f = compose(compose(bind(sine), bind(cube)), bind(cube));
f([3, ''])

var f1 = compose(bind(sine), compose(bind(cube), bind(cube)));
f1([3,''])
>>>
[0.956, 'cube was called.cube was called.sine was called.']
[0.956, 'cube was called.cube was called.sine was called.']
 
这里f和f1代表的调用顺序说明满足结合律,同时这个二元运算符就是compose函数。

那如何找到这样一个e,使得a*e=e*a=a

// unit :: Number -> (Number,String)
var unit = function(x) { return [x, ''] };

var f = compose(bind(sine), bind(cube));

compose(f, bind(unit)) = compose(bind(unit), f) = f
这里的e就是bind(unit)了。

参考链接:

  1. Translation from Haskell to JavaScript of selected portions of the best introduction to monads I've ever read
  2. 我所理解的monad