typescript - Suoritetaan TaskEither-taulukko rinnakkain, mutta jatketaan, jos yksi tai useampi tehtävä epäonnistuu


Minun täytyy tehdä sarja IO-kutsuja rinnakkain ja yhdistää kutsujen sisältö, jos ne onnistuvat. Jos yksi epäonnistuu, muut käsitellään normaalisti, mutta virheilmoitus annetaan.

Ajatusprosessini siitä, miten tämä voidaan toteuttaa:

Array<TE<E, A>> -> TE<E, Array<A>> -> TE<E, MergedA> -> [E, A]

Mitä teen tällä hetkellä:

Sekvensoin parhaillani TE:n taulukkoa, mutta mikä tahansa ketjun epäonnistuminen tuottaa vasemman.

pipe(
sequenceT(TE.taskEither)(arrayofTE), //TE<E,A>[] -> TE<E,A[]>
TE.map(mergeFn), //TE<E, A[]> -> TE<E, MergedA> 
???
)

Kuinka voin estää oikosulun?

Vastaus #1

Voit antaa T.task TE.taskEither sijasta sequence/sequenceT -funktioille (dokumentaatio):

Toiminto: suorita joukko tehtäviä rinnakkain, keräten kaikki epäonnistumiset ja onnistumiset

TaskEither: array.sequence(T.task)(taskEithers) - sama kuin sequenceT

sequence: Suoritetaan samantyyppiset tehtävät rinnakkain

import { pipeable as P, taskEither as TE, task as T, array as A, either as E } from "fp-ts";

const arrayofTE: TE.TaskEither<string, number>[] = [
  TE.right(1),
  TE.right(2),
  TE.left("Oh shit")
];

const run = P.pipe(
  // change to T.task instead of TE.taskEither here
  A.array.sequence(T.task)(arrayofTE),
  mergeFn
);

run(); // run side effect
// returns Promise<{"errors":["Oh shit"],"results":[1,2]}>

// whatever merged result you want to have; this one collects all errors and all results
declare function mergeFn(te: T.Task<E.Either<string, number>[]>): T.Task<Results> 

type Results = { errors: string[]; results: number[] };

sequenceT: Suoritetaan tehtäviä eri tyypillä rinnakkain

import { apply as AP /* and others above */ } from "fp-ts";

// Here, TaskEither result can be number | boolean (success case), string on error
const arrayofTE = [TE.right(1), TE.right(true), TE.left("Oh shit")] as const;

const run = P.pipe(
  AP.sequenceT(T.task)(...arrayofTE), // we use sequenceT here and pass T.task again
  mergeFn
);

declare function mergeFn(a: T.Task<E.Either<string, number | boolean>[]>): T.Task<Results>

Tässä on hiekkalaatikoita, joissa on mergeFn-toteutus, joiden kanssa voi leikkiä: sequence, sequenceT.

Vastaus #2

sequenceT fp-ts 2.16.1:n kanssa, jossa TE.taskStream on vanhentunut

import { sequenceT } from "fp-ts/lib/Apply.js"
import * as TE from "fp-ts/lib/TaskEither.js"

await pipe(
    sequenceT(TE.ApplyPar)(
      checkAuth(event),
      getDocs(event),
    ),
    TE.map(([auth, docs]) => {
      if (!auth) throw new Error("Unauthorized")
      return docs
    }),
    TE.map(flattenDocs),
)()

Aiheeseen liittyviä artikkeleita