这是一个单子吗?
我试图理解 monad 的概念,我想知道这段代码是否是这个概念的实现(在 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,则返回 60 。
var foo = {
x: 10,
add: function(x) {
this.x += x;
}
};
M(foo).add(10).add(20).add(30).x
将返回 70
函数被包装在 M 对象内,因此方法内的 this 上下文始终是该 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
I'm trying to understand the concept of monads and I want to know if this code is an implementation of this concept (in JavaScript).
I have function M which return new object that have set method which create wrapper method
var foo = M().set('getX', function() {
return this.x;
}).set('setX', function(x) {
this.x = x;
}).set('addX', function(x) {
this.x += x;
});
And then I can chain method of foo
foo.setX(10).addX(20).addX(30).getX()
will return 60
and the same if I have object with methods and call M with this object.
var foo = {
x: 10,
add: function(x) {
this.x += x;
}
};
M(foo).add(10).add(20).add(30).x
will return 70
Functions are wrapped inside M object so the this context inside method is always that M object.
f = M({x: 20}).set('getX', function() {
return this.x;
}).set('addX', function(x) {
this.x += x;
}).addX(10).getX
so f is function with context of object wrapped by M — if I call f()
it will return 30.
Am I understand this correctly? Is M a monad?
EDIT modified code is on github https://github.com/jcubic/monadic
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个幺半群模式。每个状态更新操作(例如
.setX(10)
、.addX(20)
等)都是一种转换一个对象的计算。 (为了在语法上有效,您必须将其编写为单参数函数function(x) {x.addX(20);}
,但我认为如果我使用缩写形式会更清楚.)有两件事使它成为一个幺半群。首先,有一个标识元素:
.addX(0)
对其对象不执行任何操作。其次,任意两个操作可以组合。例如,.setX(10).addX(20)
也是一种转换一个对象的计算。它不是一个单子。您的方法支持的计算仅限于编写和更新
this.x
。 (.getX()
不是幺半群的成员,因为你不能在它后面链接任何东西)。例如,使用 monad,您可以让操作链中的一个成员执行 if-then-else 来决定链中接下来发生的事情。你的方法做不到这一点。This is a monoid pattern. Each state-updating operation, such as
.setX(10)
,.addX(20)
, and so forth, is a computation that transforms one object. (To be syntactically valid, you would have to write it as a one-parameter functionfunction(x) {x.addX(20);}
, but I think it's clearer if I use the short form.)Two things make this a monoid. First, there is an identity element:
.addX(0)
does nothing to its object. Second, any two operations can be combined. For example,.setX(10).addX(20)
is also a computation that transforms one object.It is not a monad. The computations supported by your methods are limited to writing and updating
this.x
. (.getX()
is not a member of the monoid because you can't chain anything after it). For example, with a monad you can have one member of a chain of operations execute an if-then-else to decide what comes next in the chain. Your methods can't do that.抛开可变性不谈;据我了解,您所写的内容比单子或幺半群更接近于应用函子。
同样,根据我的理解,幺半群是一个在将单个类型映射到其自身的单个操作下封闭的组(在抽象代数意义上)。如果您仅实现了
add
,那么您可能说您的原型链实现了幺半群。但即便如此,您也必须自己在每个参数之间手动指定归约作为二元运算,如下所示:但是由于您已将不确定数量的函数绑定到类型 (
M< /code>),它们都知道如何“解开”该类型,应用预期的函数,然后在退出时恢复“包装器”,然后您就拥有了一种应用函子。
如果您找到了某种方法来组合在
M
上运行的所有函数的范围,那么您将更接近单子实现:此类实现很棘手,但使您能够对它们进行切片和切块分成小块,和/或由较小的块组成较大的块。
Mutability aside; to my understanding, what you have written is closer to an applicative functor than either a monad, or a monoid.
Again, to my understanding, a monoid is a Group (in the abstract algebraic sense) closed under a single operation mapping a single type unto itself. If you had only implemented
add
then you might say that your prototype chain implemented a monoid. But even then, you would have to specify the reduction yourself, by hand, as a binary operation, between each, and every argument, like so:But since you have bound an indeterminate number of functions to a type (
M
), which all know how to 'unwrap' that type, apply the intended function, then restore the 'wrapper' on exit, then you have a sort of applicative functor.If you had found some way to compose the scopes of all functions operating on
M
, then you would be closer still to a monadic implementation:Such implementations are tricky, but give you the ability to slice and dice them into little pieces, and/or compose larger ones from smaller ones.