Управление массивом монад в fp-ts и функциональном программировании - PullRequest
0 голосов
/ 10 апреля 2020

Я очень новичок в функциональном программировании, и я очень много борюсь с бегом по массивам.

Когда я читаю эту книгу , мне кажется, что я должен просто перебираю монады, но я не могу обернуть голову вокруг этой концепции с помощью fp-ts .

Может кто-нибудь объяснить следующее, используя array.traverse/sequence или любым другим способом, пожалуйста?

  1. Как мне go с TaskEither<Error, string[]> до TaskEither<Error, Either<Error, string>[]>; или есть ли лучший способ сделать go из одной ошибки во вложенные ошибки, сохраняя простоту ввода?
  2. Как я могу go из TaskEither<Error, Either<Error, string[]>> в нечто вроде TaskEither<Error, Option<string[]>> или что-то подобное; или мы должны отобразить результат этой функции, чтобы вернуться к Either?

Рассмотрим следующий упрощенный код, чтобы лучше понять, что мы делаем с этими массивами:

// helper functions
declare function toItems(input: string): TaskEither<Error, string[]);
declare function toTitle(item: string): Either<Error, string>;
declare function clean(item: string): Option<string>;

// This is what I tried so far
const program = (input: string) => pipe(
  toItems(input), // we have TaskEither<Error, string[]>
  TE.map(items => array.traverse(either)(items, toTitle)), // now we have TaskEither<Error, Either<Error, string[]>>
  TE.map(items => array.traverse(option)(items, clean)), // nothing works with clean() from here
)

1 Ответ

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

Строго говоря, Аппликативный достаточно для traverse - вам не нужна монада.

TaskEither<Error, string[]> до TaskEither<Error, Either<Error, string>[]>?

const program1 = (input: string) =>
  P.pipe(
    toItems(input),
    TE.map(A.map(toTitle))
  );

TaskEither<Error, Either<Error, string[]>> до TaskEither<Error, Option<string[]>>?

const program2 = (input: string) =>
  P.pipe(
    toItems(input),
    TE.map(items => A.array.traverse(O.option)(items, clean))
  );

Конкретная выбранная конструкция зависит от вашей среды и цели. ▶ Option: акцент на отсутствие / присутствие; ▶ Either: допускает более конкретный тип ошибки в Left.


Давайте рассмотрим некоторые программы и представим, что все используют веб-API с TaskEither.

Программа 3: (input: string) => TE.TaskEither<Error, string[]>

▶ либо потерпит неудачу полностью с Error, либо преуспеет с string[] извлеченными данными

Программа 4: (input: string) => TE.TaskEither<Error, E.Either<Error, string[]>>

fetch приведет к Error или преуспевает. В случае успеха обработайте веб-данные дальше - в результате Error или string[]

Программа 5: (input: string) => TE.TaskEither<Error, E.Either<Error, string>[]>

▶ такая же, как и в Программе 4, но пост-обработка веб-данных приводит к несколько Either результатов - каждый может потерпеть неудачу или преуспеть индивидуально


Вот реализация программы 4 в качестве некоего промежуточного положения:

const program4 = (
  input: string
): TE.TaskEither<Error, E.Either<Error, string[]>> =>
  P.pipe(
    toItems(input), // TE.TaskEither<Error, string[]>
    TE.map(items => // TE.TaskEither<E, E.Either<Error, string[]>>
      A.array.traverse(E.either)( // E.Either<Error, string[]>
        items,
        F.flow( // E.Either<Error, string>
          toTitle,
          E.chain(s => E.fromOption(() => Error())(clean(s)))
        )
      )
    )
  );

Codesandbox

...