在 fp-ts 中合并 2 个 TaskEither

merging 2 TaskEither in fp-ts

我正在做一个使用 fp-ts

的项目

我有 2 个 TaskEither 对象,如 TaskEither、TaskEither

我想合并这个对象的内容并创建新的 TaskEither,
Example A object = {a: 123, b: 456, c: 0}

Example B object = {c: 789}

我想创建newObject: TaskEither<ErrorA, A>

如果一切顺利,期望值应该是{a: 123, b: 456, c: 789 }

我建议在这种情况下使用 Do-Notation。举个例子。

import { pipe } from 'fp-ts/function'
import * as TE from 'fp-ts/TaskEither'

interface A {
  a: number
  b: number
  c: number
}

interface B {
  c: number
}

const a = TE.right<Error, A>({ a: 123, b: 456, c: 0 })
const b = TE.right<Error, B>({ c: 789 })

const c: TE.TaskEither<Error, A> = pipe(
  TE.Do,
  TE.apS('a', a),
  TE.apS('b', b),
  TE.map(({ a, b }) => ({ ...a, ...b }))
)

如果错误类型不同,您应该考虑将错误包装在联合类型中。在 fp-ts Issue Tracker.

中有一个更长的话题

使用TE.Do当然是一个解决方案(干净又小)。 对于另一种用法,您可以使用管道链接您的任务。

export const a = (): TE.TaskEither<ErrorA, A> => {
  return TE.right({ a: 123, b: 456, c: 0 });
}

export const b = (): TE.TaskEither<ErrorB, B> => {
  return TE.right({ c: 789 });
}

export const c =(): TE.TaskEither<ErrorA, A> => {
  return pipe(
    a(),
    TE.chain(a => {
      return pipe(
        b(),
        TE.map(b => {
          return {
            ...a,
            c: b.c,
          }
        }),
      );
    }),
  );
}

如果您正在处理同一个应用程序的所有事物(并且回想一下所有 monad 都是应用程序),最直接的方法是:

type A = { /*...*/ }
type B = { /*...*/ }

declare const a: TaskEither<string, A>
declare const b: TaskEither<string, B>

sequenceS(TE.ApplyPar)({ a, b }) // TaskEither<string, { a: A, b: B }>; could also use TE.ApplySeq instead for sequential instead of parallel processing of async calls

如果 ab 为左,则 TaskEither 将产生左。

sequence 变体(共有三个,Apply.sequenceS、Apply.sequenceT 和 Array.sequence)专门用于执行您的要求:采取 record/array 的单子,如果它们都“成功”,则会产生 record/array 个结果。否则你会遇到一个“失败”。

declare const firstOpt: () => Option<string>
declare const secondOpt: () => Option<number>
sequenceT(Option.Apply)(firstOpt(), secondOpt())
// None or Option<[string, number]>

declare const firstEither: () => Left<string>
declare const secondEither: () => Right<number>
sequenceS(Either.Apply)({
  first: firstEither(),
  second: secondEither(),
})
// Left<string>

等等