我有一个实体列表,即使一次验证失败也会产生错误。然而,我仍然想迭代整个列表,并收集所有错误以进行进一步的日志记录。
具有默认"任一应用程序"的遍历/序列将产生Either<E, A[]>
(仅第一次遇到错误(,而不是所需的Either<E[], A[]>
。
库中是否有默认的工具来实现这一点,或者可以通过编写自定义应用程序来实现?
没有fp-ts函数可以直接执行此操作,但您可以使用Either
模块中的getApplicativeValidation
:
import * as E from 'fp-ts/lib/Either'
import * as RA from 'fp-ts/lib/ReadonlyArray'
import {pipe} from 'fp-ts/lib/function'
const collectErrors = <E, A>(
xs: readonly E.Either<E, A>[]
): E.Either<readonly E[], readonly A[]> =>
pipe(
xs,
RA.traverse(E.getApplicativeValidation(RA.getSemigroup<E>()))(
E.mapLeft(RA.of)
)
)
// Left(['a', 'b'])
collectErrors([E.left('a'), E.right(1), E.left('b'))])
// Right([1, 2])
collectErrors([E.right(1), E.right(2)])
// Right([])
collectErrors([])
其工作原理是getApplicativeValidation
获取一个Semigroup
实例并返回一个可与traverse
一起使用的Applicative
实例。应用实例将使用半群实例组合错误。
RA.traverse(
// The applicative instance for the either that will collect the errors
// into an array
E.getApplicativeValidation(
// The semigroup instance for readonly E[], which concatenates the arrays
RA.getSemigroup<E>()
)
)(
// Turn each Either<E, A> into Either<readonly E[], A> by putting each error
// inside an array so they can be concatenated
E.mapLeft(RA.of)
)