如何在 fp-ts 中组合 Either 对象的左侧?
How to combine the left sides of Either objects in fp-ts?
我有两个验证函数用于 return Either
的不同值。如果其中一个具有 left
值,我想抛出一个异常,如果两者都是 right
,我什么都不做。我以前从未使用过 fp-ts,也不知道如何正确组合左结果。我当前的解决方案有效,但感觉我没有正确使用它。
import { Either, left, right, isLeft, getOrElse } from 'fp-ts/lib/Either';
function validateMonth( m: Month ): Either<Error, Month> {
return m.isInRange() ? right(m) : left(new Error('Month must be in range!'));
}
function validateYear( y: Year ): Either<Error, Year> {
return year.isBefore(2038) ? right(y) : left(new Error('Year must be before 2038!'));
}
function throwingValidator(m: Month, y: Year): void {
// todo: Refactor to get rid of intermediate variables,
// combining results of validateMonth and validateYear into a type
// of Either<Error, Unit>
const monthResult = validateMonth( month );
const yearResult = validateYear( year );
const throwOnError = (e: Error) => { throw e; };
if ( isLeft( monthResult ) ) { getOrElse(throwOnError)(monthResult); }
if ( isLeft( yearResult ) ) { getOrElse(throwOnError)(yearResult); }
}
我已经阅读了https://dev.to/gcanti/getting-started-with-fp-ts-either-vs-validation-5eja的介绍,但是该代码与我想要的完全相反:我不关心验证后的输入值,只想return发生的第一个错误。
您可能正在寻找类似
的内容
const toPromise = fold(e => Promise.reject(e), r => Promise.resolve(r));
Promise.all([
toPromise(validateMonth(month)),
toPromise(validateYear(year)),
]).then(([validMonth, validYear]) => {
return …
});
或更实用的方式
toPromise(ap(ap(of(validMonth => validYear => {
return …
}), validateMonth(month)), validateYear(year)))
您还可以用 array.sequence
做 Promise.all
,然后再做 toPromise
。
一般忽略 throwingValidator
并抛出(这首先违背了使用 fp-ts
的目的)并仅关注此特定请求:
Refactor to get rid of intermediate variables, combining results of validateMonth and validateYear into a type of Either
您可能正在寻找:
const monthAndYearResult: Either<
Error,
{ month: Month, year: Year }
> = sequenceS(either)({
month: validateMonth(month),
year: validateYear(year)
})
"sequence"ing 通常需要 Traversable
的实例(在这种情况下是结构 { year, month }
)和 Applicative
的实例(either
在在这种情况下),语义是将不同的独立计算聚合在一起的语义。
如果您明确想要忽略结果,通常会提供一个 _
后缀替代方案来完成此操作,但目前 fp-ts
v2 中还没有。
要获得 Either<Error, void>
,您可以采用:
const result = pipe(
sequenceS(E.either)({ month: validateMonth(month), year: validateYear(year) }),
E.map(constVoid)
)
请注意,sequenceS
只是可能的选项之一,您可以使用 sequenceT
或 array.sequence
来获得类似的结果,例如:
pipe(
sequenceT(either)([validateMonth(month), validateYear(year)]),
E.map(constVoid)
)
我有两个验证函数用于 return Either
的不同值。如果其中一个具有 left
值,我想抛出一个异常,如果两者都是 right
,我什么都不做。我以前从未使用过 fp-ts,也不知道如何正确组合左结果。我当前的解决方案有效,但感觉我没有正确使用它。
import { Either, left, right, isLeft, getOrElse } from 'fp-ts/lib/Either';
function validateMonth( m: Month ): Either<Error, Month> {
return m.isInRange() ? right(m) : left(new Error('Month must be in range!'));
}
function validateYear( y: Year ): Either<Error, Year> {
return year.isBefore(2038) ? right(y) : left(new Error('Year must be before 2038!'));
}
function throwingValidator(m: Month, y: Year): void {
// todo: Refactor to get rid of intermediate variables,
// combining results of validateMonth and validateYear into a type
// of Either<Error, Unit>
const monthResult = validateMonth( month );
const yearResult = validateYear( year );
const throwOnError = (e: Error) => { throw e; };
if ( isLeft( monthResult ) ) { getOrElse(throwOnError)(monthResult); }
if ( isLeft( yearResult ) ) { getOrElse(throwOnError)(yearResult); }
}
我已经阅读了https://dev.to/gcanti/getting-started-with-fp-ts-either-vs-validation-5eja的介绍,但是该代码与我想要的完全相反:我不关心验证后的输入值,只想return发生的第一个错误。
您可能正在寻找类似
的内容const toPromise = fold(e => Promise.reject(e), r => Promise.resolve(r));
Promise.all([
toPromise(validateMonth(month)),
toPromise(validateYear(year)),
]).then(([validMonth, validYear]) => {
return …
});
或更实用的方式
toPromise(ap(ap(of(validMonth => validYear => {
return …
}), validateMonth(month)), validateYear(year)))
您还可以用 array.sequence
做 Promise.all
,然后再做 toPromise
。
一般忽略 throwingValidator
并抛出(这首先违背了使用 fp-ts
的目的)并仅关注此特定请求:
Refactor to get rid of intermediate variables, combining results of validateMonth and validateYear into a type of Either
您可能正在寻找:
const monthAndYearResult: Either<
Error,
{ month: Month, year: Year }
> = sequenceS(either)({
month: validateMonth(month),
year: validateYear(year)
})
"sequence"ing 通常需要 Traversable
的实例(在这种情况下是结构 { year, month }
)和 Applicative
的实例(either
在在这种情况下),语义是将不同的独立计算聚合在一起的语义。
如果您明确想要忽略结果,通常会提供一个 _
后缀替代方案来完成此操作,但目前 fp-ts
v2 中还没有。
要获得 Either<Error, void>
,您可以采用:
const result = pipe(
sequenceS(E.either)({ month: validateMonth(month), year: validateYear(year) }),
E.map(constVoid)
)
请注意,sequenceS
只是可能的选项之一,您可以使用 sequenceT
或 array.sequence
来获得类似的结果,例如:
pipe(
sequenceT(either)([validateMonth(month), validateYear(year)]),
E.map(constVoid)
)