【发布时间】:2014-01-10 19:36:03
【问题描述】:
现在node.js 支持ECMAScript Harmony generators,我们可以在Haskell 中简洁地编写单子代码ala do 块:
function monad(unit, bind) {
return function (f) {
return function () {
var g = f.apply(this, arguments);
return typeOf(g) === "Generator" ? send() : unit(g);
function send(value) {
var result = g.next(value);
if (result.done) return unit(result.value);
else return bind(result.value, send);
}
};
};
}
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
在上面的代码中,monad 是一个函数,可用于创建 deterministic monad,例如:
var maybe = monad(function (a) {
return {just: a};
}, function (m, f) {
return m === null ? null : f(m.just);
});
您现在可以按如下方式使用maybe:
var readZip = maybe(function * (a, b) {
var a = yield readList(a);
var b = yield readList(b);
return _.zip(a, b);
});
上面的函数readZip 接受两个字符串,将它们转换成列表,然后压缩它们。如果有错误,它会立即返回null。这取决于以下函数:
function readList(string) {
try {
var value = JSON.parse(string);
return value instanceof Array ? {just: value} : null;
} catch (error) {
return null;
}
}
我们对其进行测试以检查它是否按预期工作:
console.log(readZip('[1,2,3,4]', '["a","b"]')); // [[1,"a"],[2,"b"],[3,"c"]]
console.log(readZip('hello', '["a","b"]')); // null
console.log(readZip('[1,2,3,4]', 'world')); // null
类似地,我们可以创建任何其他确定性 monad。例如,我最喜欢的 cont monad:
var cont = monad(function (a) {
return function (k) {
return k(a);
};
}, function (m, k) {
return function (c) {
return m(function (a) {
return k(a)(c);
});
};
});
现在我们可以使用cont 简洁地创建延续传递风格的函数:
var fib = cont(function * (n) {
switch (n) {
case 0: return 0;
case 1: return 1;
default:
var x = yield fib(n - 1);
var y = yield fib(n - 2);
return x + y;
}
});
您可以使用fib函数如下:
fib(10)(function (a) { console.log(a); }); // 55
不幸的是,monad 仅适用于确定性单子。它不适用于像 list monad 这样的非确定性 monad,因为您只能从特定位置恢复生成器一次。
所以我的问题是:有没有其他方法可以在 JavaScript 中简洁地实现非确定性 monad,例如 list monad?
【问题讨论】:
-
@elclanrs 那是作弊。它可以工作,但由于您正在构建一个全新的函数,因此无法在调用站点保留原始函数的词法环境。
-
你到底是什么意思?你能详细说明一下吗?
-
您可以为nicer syntax 使用Coffeescript 或Livescript 之类的东西,或者它不是一个选项?
-
LiveScript 绝对值得。我已经切换了:)。检查我的答案,看看是否有帮助。
标签: javascript node.js generator monads ecmascript-harmony