Как объединить левые части объектов Either в fp-ts? - PullRequest
0 голосов
/ 18 сентября 2019

У меня есть две функции проверки для разных значений, которые возвращают 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, но этот код в точности противоположен тому, что я хочу:Меня не волнует входное значение после проверки, и я хочу вернуть только первую ошибку.

Ответы [ 2 ]

1 голос
/ 23 сентября 2019

Игнорирование throwingValidator и бросок в целом (какой вид поражения цель использования fp-ts в первую очередь) и фокусировка только на этом конкретном запросе:

Refactor, чтобы избавиться отпромежуточные переменные, объединяющие результаты validateMonth и validateYear в тип Either

Вы, вероятно, ищете:

const monthAndYearResult: Either<
  Error,
  { month: Month, year: Year }
> = sequenceS(either)({
  month: validateMonth(month),
  year: validateYear(year)
})

для "последовательности" в общем случае требуется экземпляр 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)
)
1 голос
/ 19 сентября 2019

Вы, вероятно, ищете что-то вроде

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)))

Вы также можете сделать Promise.all с array.sequence и toPromise потом.

...