Fluture bimap和fold有什么区别?何时应使用它们?

时间:2018-07-19 15:08:31

标签: javascript functional-programming future fluture

背景

我正在使用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,但我不明白为什么。

问题

  1. 何时应使用bimap,何时应使用fold
  2. 它们之间的主要区别是什么?

2 个答案:

答案 0 :(得分:1)

一个人可能会使用bimap在单个步骤中同时映射拒绝分辨率,而Future将保持被拒绝< / em>或已解决,并进行了新的计算。

另一方面,fold将同时处理拒绝分辨率,以始终产生分辨率(您可以折叠两种情况都归为决议之一)。可以使用fold将两个结果都包装为另一种类型(例如Future Either a b)或将任何分支视为成功

因此,bimapfold有所不同,因为第一个将两种情况都映射,第二种将两种情况都转化为决议

示例: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)

示例:fold

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)

请注意,fold是如何完全保证eventualNumber2决议,所以我使用Future.value仅处理决议!

答案 1 :(得分:1)

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

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

差别很小,但很明显。有两个主要区别:

  1. 第二个参数的返回值不同:在bimap中,两个 函数允许返回不同的类型。在fold中,两个函数 必须返回相同类型的值。
  2. 最终的返回值是不同的:在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)