Как мне избежать вложенных монад в fp-ts или элегантно с ними справиться? - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть последовательность кода, которая должна пройти через следующие шаги (псевдокод):

  jobsRepository.findById // <-- this returns a TaskEither
  jobs.openJob // <-- jobs.openJob returns an Either
  jobsRepository.update // <-- this returns another TaskEither
  createJobOpenedEvent // simple function that returns an IJobOpenedEvent
                       // given an IOpenJob

Если я сопоставлю / объединю эти шаги вместе, я получу тип типа TaskEither<IError, Either<IError, TaskEither<IError, IOpenJob>>>, которыйочевидно, немного неловко.

Мое текущее решение для объединения всего этого в простой тип TaskEither<IError, IJobOpenedEvent> выглядит следующим образом (реальный код):

import { flatten } from "fp-ts/lib/Chain";
import { Either, either, left, right } from "fp-ts/lib/Either";
import {
  fromEither,
  TaskEither,
  taskEither,
  tryCatch,
} from "fp-ts/lib/TaskEither";

const createJobOpenedEvent = (openJob: jobs.IOpenJob): IJobOpenedEvent => ({
  name: "jobOpened",
  payload: openJob,
});

export const openJobHandler = (
  command: IOpenJobCommand
): TaskEither<IError, IJobOpenedEvent> =>
  flatten(taskEither)(
    flatten(taskEither)(
      jobsRepository
        .findById(command.jobId) // <-- this returns a TaskEither<IError, IJob>
        .map(jobs.openJob) // <-- jobs.openJob returns an Either<IError, IOpenJob>
        .map(fromEither)
        .map(jobsRepository.update) // <-- this returns a TaskEither<IError,IOpenJob>
    )
  ).map(createJobOpenedEvent);


Мой вопрос -Есть ли лучший способ справиться с этим вложением?Я чувствую, что делаю это неправильно, поскольку я новичок в функциональном программировании и не понимаю всей теории.Все вложенные flatten(taskEither) вызовы и преобразование Either в TaskEither с fromEither кажутся мне плохими.

Любая помощь очень ценится!

1 Ответ

0 голосов
/ 12 февраля 2019

Спасибо Берги за его комментарий. Мне удалось найти следующее решение, используя chain вместо map:

export const openJobHandler = (
  command: IOpenJobCommand
): TaskEither<IError, IJobOpenedEvent> =>
  jobsRepository
    .findById(command.jobId)
    .map(jobs.openJob)
    .chain(fromEither)
    .chain(jobsRepository.update)
    .map(createJobOpenedEvent)

...