背景
我正在使用Fluture抽象期货。
假设我有一个发出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,其中拒绝包含从左函数返回的类型的值,
并且分辨率包含从右侧返回的类型的值
功能。在
fold
中,拒绝端包含一个全新的类型变量,该变量尚未受到限制,并且分辨率方面包含
由两个函数返回的类型。
那是一个相当大的数目,并且可能很难解析。我将尝试在图表中将其可视化。
对于
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)
就像做compose (mapRej (f)) (map (g))
。您可以随时将
fold
移至分辨率科。就您而言,这就是您想要的。您的示例不这样做的原因
之所以工作,是因为您必须拥有未来的未来
展平:
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/