代码之家  ›  专栏  ›  技术社区  ›  Flame_Phoenix

fluture bimap和fold,有什么区别?我应该什么时候使用它们?

  •  1
  • Flame_Phoenix  · 技术社区  · 6 年前

    背景

    我在用 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软件 :将左函数映射到拒绝值上,或将右函数映射到分辨率值上,具体取决于存在的值。

    折叠 :将左函数应用于拒绝值,或将右函数应用于分辨率值,具体取决于存在的分辨率值,并与结果一起解决。

    问题

    如果你有敏锐的眼光,你就会知道我的榜样 工作。我需要使用 bimap软件 ,但我不明白为什么。

    问题

    1. 我应该什么时候用 bimap软件 我应该什么时候用 折叠 是吗?
    2. 他们之间的主要区别是什么?
    2 回复  |  直到 6 年前
        1
  •  1
  •   Avaq    5 年前

    让我们首先检查它们各自的类型签名:

    bimap :: (a -> c) -> (b -> d) -> Future a b -> Future c d
    fold  :: (a -> c) -> (b -> c) -> Future a b -> Future d c
    

    差别是相当微妙的,但显而易见。有两个主要区别:

    1. 第二个参数的返回值不同:in bimap ,两者 函数可以返回不同的类型。在 fold ,两种功能 必须返回相同类型的值。
    2. 最终返回值不同:in bimap软件 ,你回到了一个未来 拒绝包含从左函数返回的类型值, 并且解析包含从右边返回的类型的值 功能。在 折叠 ,拒绝端包含一个全新的类型变量 尚未受到限制,并且分辨率侧包含 返回的类型 二者都 功能。

    这是一个相当大的嘴巴,可能有点难以分析。我试着用图表把它形象化。

    为了 bimap软件 ,如下所示。这两个分支不相互作用:

                 rej(x)  res(y)
                     |       |
                     |       |
    bimap(f)(g):   f(x)    g(y)
                     |       |
                     V       V
    

    为了 折叠 ,拒绝分支类型为“停止”,再利用分支将 继续返回值 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)) 是的。

    你可以用 折叠 当你想把你的拒绝变成决议的时候 分支。对你来说,这就是你想要的。你的例子没有 工作是因为你最终拥有了一个未来,你必须 扁平化:

    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
    

    在函数式编程中,单子平坦化非常常见,并且通常是 打电话 join ,其实现方式如下:

    const join = chain(x => x)
    
        2
  •  1
  •   Matías Fidemraizer    6 年前

    一个人可以用 bimap 两张地图 拒绝 分辨率 一步到位, Future 将继续 拒绝 断然的 一个新的计算。

    另一方面, fold 两者兼得 拒绝 分辨率 总是产生 分辨率 (你把两个箱子都折成 分辨率 一个)一个人会用 折叠 将两个结果包装成另一种类型(例如 Future Either a b )或将任何分支视为 成功的 是的。

    因此, bimap软件 不同于 折叠 因为第一个映射两种情况,而第二个将两种情况都转换为 分辨率 是的。

    样品: bimap软件 以下内容:

    const flag = true
    const eventualNumber1 = !flag ? Future.reject (1) : Future.of (2)
    const eventualNumber2 = Future.bimap (x => x * 2) (x => x + 1) (eventualNumber1)
    
    // it'll output 3. 
    Future.fork (console.log) (console.log) (eventualNumber2)
    

    样品: 折叠 :

    const flag = false
    const eventualNumber1 = !flag ? Future.reject (1) : Future.of (2)
    const eventualNumber2 = Future.fold (x => x * 2) (x => x + 1) (eventualNumber1)
    
    // It'll output 2 even when the Future represents a rejection
    Future.value (console.log) (eventualNumber2)
    

    注意如何 折叠 我保证 eventualNumber2 是一个 分辨率 ,所以我用 Future.value 只处理决议!

    推荐文章