当我在阅读了几十篇教程后了解了 monad 时,我正在尝试在 JavaScript 中实现该模式。我正在使用LiveScript和Prelude来翻译一些 Haskell monad 示例。
所以我试图作为练习实现的 monad 是 List monad。我在 LiveScript 中写了以下内容:
List = do ->
# unit :: a -> ma
unit = (a) -> [a]
# bind :: ma -> (a -> mb) -> mb
bind = (ma, f) --> concat (map f) ma
# lift :: (a -> b) -> ma -> mb
lift = (f, ma) --> bind ma, (a) -> unit f a
{unit, bind, lift}
add1 = (x) -> x+1
let {unit, bind} = List
x <- bind [1]
y <- bind [2]
z <- bind [3]
unit add1 x+y+z #=> [7]
(List.lift add1) [1 2 3] #=> [2 3 4]
将函数嵌套在同一缩进级别的 LiveScript 语法非常方便,但它显然会转化为 JavaScript 回调地狱:
List = function(){
var unit, bind, lift;
unit = function(a){
return [a];
};
bind = curry$(function(ma, f){
return concat(map(f)(ma));
});
lift = curry$(function(f, ma){
return bind(ma, function(a){
return unit(f(a));
});
});
return { unit: unit, bind: bind, lift: lift };
}();
add1 = function(x){
return x + 1;
};
(function(arg$){
var unit, bind;
unit = arg$.unit, bind = arg$.bind;
bind([1], function(x){
return bind([2], function(y){
return bind([3], function(z){
return unit(add1(x + y + z));
});
});
});
}.call(this, List));
List.lift(add1)([1, 2, 3]);
我想要的是在接收器上实现模式以便能够像这样使用它:
List([1]).bind([2]).bind([3]).do(function(x,y,z){ x+y+z });
在观看了 Crockford 用 JavaScript(代码)解释 monad 的视频后,我了解到他提出的只是一个对象,其方法也可以用原型实现。该方法是构造函数,是一个实例方法,它使用给定的参数对值运行函数。然后向原型添加一个新方法,该方法在单值上运行给定函数。MONAD
unit
bind
lift
但是,它是真正的单子还是像 jQuery 这样的单子模式?我对 monad 的这种特殊解释有疑问,因为没有计算序列,该bind
方法立即运行函数并返回“monad”的新实例,它不是组合,就像我在 LiveScript 中实现的基于关于 Haskell 的例子。
所以我的问题是:
- 我对 monad 的实现是否正确?
- Crockford对 monad 的实现是否正确?