我有兴趣在我的 JavaScript 函数组合中尝试类似 Haskell 的 IO monad。
像Folktale的Task似乎与 Haskell 的 IO 相似,因为它是惰性的,因此在技术上是纯粹的。它代表将来可能发生的动作。但我有几个问题。
当所有后面的函数都依赖于组合中初始不纯函数的返回值时,如何形成函数组合?必须首先运行实际的任务,将返回的数据隐式传递给更远的函数。一个人不能只是传递一个未解决的任务来做任何有用的事情,或者可以吗?它看起来像。
compose(doSomethingWithData, getDataFromServer.run());
我可能遗漏了一些关键的东西,但这样做有什么好处?
一个相关的问题是对不纯函数的惰性求值有什么具体优势?当然,它提供了引用透明性,但理解问题的核心是不纯函数返回的数据结构。后面所有通过管道传输数据的函数都依赖于数据。那么不纯函数的引用透明性对我们有什么好处呢?
编辑:所以在查看了一些答案之后,我能够通过链接轻松地编写任务,但我更喜欢使用 compose 函数的人体工程学。这行得通,但我想知道它是否对函数式程序员来说是惯用的:
const getNames = () =>
task(res =>
setTimeout(() => {
return res.resolve([{ last: "cohen" }, { last: "kustanowitz" }]);
}, 1500)
);
const addName = tsk => {
return tsk.chain(names =>
task(resolver => {
const nms = [...names];
nms.push({ last: "bar" });
resolver.resolve(nms);
})
);
};
const f = compose(
addName,
getNames
);
const data = await f()
.run()
.promise();
// [ { last: 'cohen' }, { last: 'kustanowitz' }, { last: 'bar' } ]
然后,另一个可能与风格更相关的问题是,现在我们必须编写所有处理任务的函数,这似乎不如那些处理数组/对象的函数那么优雅和通用。