背景

我正在使用Fluture抽象期货。

假设我有一个发出GET请求的函数。此功能可以成功或失败。

发出请求后,如果成功,则打印一条消息,如果失败,则记录错误并执行命令。

axios.get(endpoint, { timeout: timeoutMs })
    .fold(
        err =>
            logger.errorAsync( err )
            .chain( ( ) => cmd.getAsync("pm2 restart app")),
        response => logger.infoAsync( "Great success!" )
    );


研究

我一直在阅读API,发现bimapfold都将函数应用于成功和错误:

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/

10-09 02:53