获取 TaskEithers 数组中的第一个成功值

Getting the first successful value in an array of TaskEithers

我是函数式编程的新手,也是 fp-ts 的新手,所以我很难理解所提供的 util 函数。我目前正在尝试弄清楚如何处理 TaskEithers 作为数组中的后备。

我有一个函数可以为某些 id 获取数据,即 returns ErrorSuccess:

declare function getData(id: number): TaskEither<Error, Success>

我想要的是一个函数,它将遍历一些 id 数组(例如 [1, 2, 3, 4]),为每个数组请求数据。它应该在第一个成功的 TaskEither 和 return Right<Success> 处停止。如果所有 TaskEither 都失败了,它应该将它们的错误收集到 Left<Error[]>.

import { map } from 'fp-ts/lib/Array';

const program: TaskEither<Error[], Success>
  = pipe(
    [1, 2, 3, 4],
    map(getData),
    /*
     * Now I have a TaskEither<Error, Success>[]
     * What comes next?
     */
  );

我试过类似的东西,但有一些明显的问题(如下所述):

import { map, sequence } from 'fp-ts/lib/Array';
import { map as mapTaskEither } from 'fp-ts/lib/TaskEither'

const program: TaskEither<Error, Success>
  = pipe(
    [1, 2, 3, 4],
    map(getData),
    sequence(taskEither), // Now this gets to a TaskEither<Error, Success[]>
    mapTaskEither(successes => successes[0])
  );

这种方法的问题

  1. 它在所有 ID 上运行 getData,第一次成功时不会短路
  2. 如果 任何 getData 错误,它就会出错。所以如果getData(4)出错,即使getData(1)成功
  3. ,整体program也会出错
  4. 它不会将错误收集到 Error[]
  5. 的数组中

感谢,我想出了一个解决方案。

给这个 util 函数起一个名字有助于提高可读性:

import { TaskEither, taskEither, swap } from 'fp-ts/lib/TaskEither';
import { sequence, map } from 'fp-ts/lib/Array';
import { pipe } from 'fp-ts/lib/function';

const firstRightOrLefts: <A, B>(taskEithers: TaskEither<A, B>[]) => TaskEither<A[], B>
    = taskEithers => pipe(
        taskEithers,
        map(swap),
        sequence(taskEither),
        swap,
    );

然后可以这样使用:

import { map } from 'fp-ts/lib/Array';

const program: TaskEither<Error, Success>
  = pipe(
    [1, 2, 3, 4],
    map(getData),
    getFirstRightOrLefts, // <-- Woohoo!
  );