在 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
如果 a
或 b
为左,则 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>
等等
我正在做一个使用 fp-ts
的项目我有 2 个 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
如果 a
或 b
为左,则 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>
等等