这是单子吗?

我试图理解单子的概念,我想知道这个代码是否是这个概念的实现(在JavaScript中)。

我有返回创建包装方法的set方法的新对象的函数M.

var foo = M().set('getX', function() { 
  return this.x; 
}).set('setX', function(x) { 
  this.x = x;
}).set('addX', function(x) { 
  this.x += x;
});

然后我可以链接foo的方法

foo.setX(10).addX(20).addX(30).getX()

将返回60

如果我有方法对象并且用这个对象调用M,那也是一样的。

var foo = {
  x: 10,
  add: function(x) {
    this.x += x;
  }
};

M(foo).add(10).add(20).add(30).x

将返回70

函数被包装在M对象中,所以这个方法内部的上下文总是那个M对象。

f = M({x: 20}).set('getX', function() {
   return this.x; 
}).set('addX', function(x) {
   this.x += x;
}).addX(10).getX

所以f是用M包装的对象的上下文的函数 - 如果我调用f()它将返回30。

我的理解是否正确? M是单子吗?

编辑修改后的代码在github上https://github.com/jcubic/monadic


这是一个monoid模式。 每个状态更新操作(如.setX(10) .addX(20)等)都是一个转换一个对象的计算。 (要语法有效,你必须把它写的一个参数的函数function(x) {x.addX(20);}但我认为这是更清楚,如果我使用简写形式)

有两件事使得这是一个monoid。 首先,存在一个标识元素: .addX(0)对其对象没有任何作用。 其次,任何两个操作可以合并。 例如, .setX(10).addX(20)也是一个转换一个对象的计算。

这不是一个monad。 您的方法支持的计算仅限于编写和更新this.x.getX()不是monoid的成员,因为你不能在它之后链接任何东西)。 例如,对于monad,您可以让一个操作链中的一个成员执行if-then-else来决定链中的下一个内容。 你的方法不能这样做。


除了突变之外; 根据我的理解,你写的东西比单子或者幺半群更接近于应用函子。

同样,就我的理解而言,幺半群是一个集合(抽象代数意义上的),它是在一个映射单一类型的操作下关闭的。 如果你只实现了add那么你可能会说你的原型链实现了一个monoid。 但即使如此,你必须自己手动指定一个二进制操作,在每个参数和每个参数之间,如下所示:

M({x:0}).add(1).add(2)...add(100) === 1050; // or _.reduce([1..100],add)

但是由于你已经将不确定数量的函数绑定到类型( M ),它们都知道如何“解开”该类型,应用预期的函数,然后在退出时恢复“包装器”,那么你有一种应用函数。

如果你已经找到某种方式来组合所有在M运行的函数的范围,那么你将更接近一元实现:

var bigOpFromLittleOps = 
       M({x:0})  .bind(function(x0){
return Madd(1)   .bind(function(x1){
return Madd(2)   .bind(function(x2){
...
return Madd(100) .bind(function(x100){
return Mreturn(x100);
}); ... });});})() === 1050; // Overkill

这样的实现是棘手的,但是让你能够将它们切成小块,并且/或者从较小的块构成更大的块。

链接地址: http://www.djcxy.com/p/47677.html

上一篇: Is this a monad?

下一篇: Does the chain function in underscore.js create a monad?