背景
我正在使用 Fluture抽象 future 。
假设我有一个发出 GET 请求的函数。此功能可能成功或失败。
发出请求后,如果成功,则打印一条消息,如果失败,则记录错误并执行命令。
axios.get(endpoint, { timeout: timeoutMs })
.fold(
err =>
logger.errorAsync( err )
.chain( ( ) => cmd.getAsync("pm2 restart app")),
response => logger.infoAsync( "Great success!" )
);
研究
我一直在阅读 API,我发现 bimap
和 fold
都对成功和错误应用了一个函数:
bimap:将左函数映射到拒绝值,或将右函数映射到分辨率值,具体取决于存在哪个。
fold:将左函数应用于拒绝值,或将右函数应用于分辨率值,具体取决于哪个函数存在,并用结果进行解析。
问题
如果您有敏锐的眼光,就会知道我的示例行不通。我需要使用 bimap
,但我不明白为什么。
问题
- 什么时候应该使用
bimap
,什么时候应该使用fold
? - 它们之间的主要区别是什么?
最佳答案
让我们首先检查一下它们各自的类型签名:
bimap :: (a -> c) -> (b -> d) -> Future a b -> Future c d
fold :: (a -> c) -> (b -> c) -> Future a b -> Future d c
差异非常细微,但显而易见。有两个主要区别:
- 第二个参数的返回值不同:在
bimap
中,两者 允许函数返回不同的类型。在fold
中,两个函数 必须返回相同类型的值。 - 最终的返回值是不同的:在
bimap
中,你得到一个 Future where 拒绝包含从左函数返回的类型的值, 并且分辨率包含从右侧返回的类型的值 功能。在fold
中,拒绝端包含一个全新的类型变量,它 尚未受到限制,决议方包含的值(value) both 函数返回的类型。
这太啰嗦了,可能有点难以解析。我将尝试在图表中将其可视化。
对于bimap
,它看起来像下面这样。这两个分支不交互:
rej(x) res(y)
| |
| |
bimap(f)(g): f(x) g(y)
| |
V V
对于 fold
,拒绝分支会“停止”,而解决分支会
继续 f(x)
的返回值或 g(y)
的返回值:
rej(x) res(y)
| |
| |
fold(f)(g): -> f(x)*g(y)
|
V
您可以随时使用bimap
更改拒绝原因和
同时分辨率值。做 bimap (f) (g)
就像做
撰写 (mapRej (f)) (map (g))
。
只要你想将拒绝移动到解决方案中,就可以使用 fold
分支。在您的情况下,这就是您想要的。你的例子没有的原因
工作是因为你最终得到了一个 future 的 future ,你必须
展平:
axios.get(endpoint, { timeout: timeoutMs })
.fold(
err =>
logger.errorAsync( err )
.chain( ( ) => cmd.getAsync("pm2 restart app")),
response => logger.infoAsync( "Great success!" )
)
.chain(inner => inner); //<-- Flatten
扁平化 Monad 在函数式编程中很常见,通常是
称为 join
,可以像这样实现:
const join = chain(x => x)
关于javascript - Fluture bimap 和 fold,有什么区别,我应该什么时候使用它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51426121/