我正在尝试理解monads的概念,我想知道这段代码是否是这个概念的实现(在JavaScript中)。
我有函数M返回具有set方法的新对象,该方法创建包装器方法
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对象中,因此方法中的this context始终是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是monad吗?
编辑修改后的代码位于github https://github.com/jcubic/monadic
答案 0 :(得分:14)
这是一种幺半群模式。每个状态更新操作,例如.setX(10)
,.addX(20)
等,都是转换一个对象的计算。 (要在语法上有效,你必须把它写成一个参数函数function(x) {x.addX(20);}
,但我认为如果我使用短格式会更清楚。)
两件事使这成为一个幺半群。首先,有一个标识元素:.addX(0)
对其对象没有任何作用。其次,可以组合任何两个操作。例如,.setX(10).addX(20)
也是一个转换一个对象的计算。
这不是一个单子。您的方法支持的计算仅限于编写和更新this.x
。 (.getX()
不是幺半群的成员,因为你不能在它之后链接任何东西)。例如,使用monad,您可以让一个操作链中的一个成员执行if-then-else来决定链中接下来会发生什么。你的方法不能那样做。
答案 1 :(得分:0)
除了可变性;根据我的理解,你所写的内容比一个monad或monoid更接近一个applicative functor。
同样,根据我的理解,monoid是一个组(在抽象代数意义上)在单操作下关闭,将单个类型映射到自身。如果你只有 实现了add
,那么你可能说你的原型链实现了一个monoid。但即使这样,你也必须亲自指定减少,作为二元操作,在每个参数和每个参数之间,如下所示:
M({x:0}).add(1).add(2)...add(100) === 1050; // or _.reduce([1..100],add)
但是因为你已经将一个不确定数量的函数绑定到一个类型(M
),它们都知道如何解开'该类型,应用预期的功能,然后恢复'包装'在退出时,你有一种应用函子。
如果您已经找到某种方法来编写在M
上运行的所有函数的范围,那么您将更接近于monadic实现:
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
这样的实现很棘手,但是你可以将它们切片并分成小片,和/或从较小的片段中构成较大的片段。