Взаимозависимые операции с функциональным программированием в TypeScript - PullRequest
0 голосов
/ 21 апреля 2020

Я работаю над приложением, написанным на функциональном TypeScript, используя fp-ts и io-ts . Мне нужно получить набор JSON файлов конфигурации. Некоторые из этих JSON файлов содержат информацию, необходимую для извлечения некоторых других JSON файлов. Мне интересно, что было бы хорошей абстракцией для таких зависимостей.

В настоящее время я нахожу себя пишущим код, который определяет жестко закодированные этапы (см. Псевдокод ниже). Проблема с этим подходом состоит в том, что названия для этих этапов совершенно бессмысленны, выражая технические детали, а не предполагаемое поведение кода.

type Stage1 = { config1: Config1 }
const stage1 = (): TaskEither<Err, Stage1> => // ...

type Stage2 = Stage1 & { config2: Config2, config3: Config3 }
const stage2 = (s1: Stage1): TaskEither<Err, Stage2> => // ...

type Stage3 = Stage2 & { config4: Config4 }
const stage3 = (s2: Stage2): TaskEither<Err, Stage3> => // ...

const complete = pipe(
  stage1(),
  chain(stage2),
  chain(stage3),
)

Я написал следующую вспомогательную функцию wheel, которая решает проблему , Остается вопрос, является ли это новым изобретением. Возможно, у этого шаблона программирования есть имя. Может быть, это уже часть fp-ts в той или иной форме.

import * as P from 'maasglobal-prelude-ts';

const wheel = <I extends {}, O extends {}, E>(cb: (i: I) => P.TaskEither<E, O>) => (
  ei: P.TaskEither<E, I>,
): P.TaskEither<E, I & O> =>
  P.pipe(
    ei,
    P.TaskEither_.chain((i) =>
      P.pipe(
        cb(i),
        P.TaskEither_.map((o) => ({ ...i, ...o })),
      ),
    ),
  );

const complete = P.pipe(
  P.TaskEither_.right({}),
  wheel(() => P.TaskEither_.right({ foo: 123 })),
  wheel(() => P.TaskEither_.right({ bar: 456 })),
  wheel(({ foo }) => P.TaskEither_.right({ quux: 2 * foo })),
  wheel(({ quux, bar }) => P.TaskEither_.right({ quuxbar: quux + '-' + bar })),
);
expect(complete).toStrictEqual({ foo: 123, bar: 456, quux: 246, quuxbar: '246-456' });

1 Ответ

1 голос
/ 24 апреля 2020

Очень похоже на то, что вы бы делали на других языках, используя нотацию do или a для понимания, или в fp-ts, используя Do:

import { Do } from 'fp-ts-contrib/lib/Do';
import { taskEither, right } from 'fp-ts/lib/TaskEither';

const complete = Do(taskEither)
  .bind('foo', right(123))
  .bind('bar', right(456))
  .bindL('quux', ({ foo }) => right(2 * foo))
  .return(({ quux, bar }) => right({ quuxbar: quux + '-' + bar }));
...