0

我正在开发一个使用fp-tsio-ts以功能型 TypeScript 编写的应用程序。我需要检索一组 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' });
4

1 回答 1

1

看起来很像在其他语言中使用 do 表示法或 for 理解,或者在 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 }));
于 2020-04-24T09:02:57.863 回答