Управление ошибками в функциональном программировании и фп-тс - PullRequest
0 голосов
/ 05 апреля 2020

Я очень новичок в функциональном программировании и особенно fp-ts.

В последнее время я борюсь с тем, чтобы поиграть с массивами и связать их в разные монады и в то же время сохранить некоторые детали, связанные с каждым step.

Допустим, у нас есть программа, которая

  1. извлекает некоторые данные в виде строки
  2. , если возможно, анализирует строку в массиве ITitle; тип может быть Option<ITitle[]>
  3. отображает их в массив возможных ITitle, выполняющих некоторые асинхронные c обновления; тип может быть TaskEither<IError, ITitle>
  4. Печатает результат (если имеется), включая сбои, с указанием их c ошибок
// error definition
enum ErrorType {
    NotFound = 'NOT_FOUND',
    Timeout = 'TIMEOUT',
    ParseFailure = 'PARSE_FAILURE',
    UpdateFailure = 'UPDATE_FAILURE',
    Unknown = 'UNKNOWN',
}
// our types
interface ITitle {
    title: string;
    meta: unknown;
}
interface IError {
    msg: string;
    type: ErrorType;
}

// helper functions
declare function findTitles(): TaskEither<IError, string>;
declare function parseTitles(items: string): Option<ITitle[]>; // or Either<IError, ITitle[]> whatever fits best
declare function updateTitle(title: ITitle): TaskEither<IError, ITitle>;

Обновление:
Я обновляю вопрос, уточняя c детали, где проблема:

const program = pipe(
  findTitles(),
  TE.map(parseTitles), // Now we get TaskEither<IError, Option<ITitle[]>>;
  TE.chain(titles =>
    // Problem is var titles is still wrapped in Option and this won't work
    // What if the titles is Either<IError, ITitle[]>?
    // How do we preserve the error if titles is an Either?
    array.traverse(taskEither)(titles, title => updateTitle(title))
  ),
  // How to log the result including the errors?
  // Or in another word how do we run traverse and fold the Eithers?
)

1 Ответ

2 голосов
/ 06 апреля 2020

TE.map(parseTitles) возвращает нам TaskEither<IError, Option<ITitle[]>>, проблема в chain обратном вызове, где titles все еще упакован в Option, и это не будет работать

Вы можете добавить другой chain, который разворачивает Option в TaskEither, используя fromOption:

const program = pipe(
  findTitles(),
  TE.map(parseTitles), // Now we have TaskEither<IError, Option<ITitle[]>>;
  TE.chain(TE.fromOption(() => ErrorType.NotFound)) // Now we have TaskEither<IError, ITitle[]>
  TE.chain(titles =>
    array.traverse(taskEither)(titles, title => updateTitle(title))
  ),
)

или fromEither:

const program = pipe(
  findTitles(),
  TE.map(parseTitles), // Now we have TaskEither<IError, Either<IError, ITitle[]>>;
  TE.chain(TE.fromEither) // Now we have TaskEither<IError, ITitle[]>
  TE.chain(titles =>
    array.traverse(taskEither)(titles, title => updateTitle(title))
  ),
)
...