1

我对函数式编程非常陌生,并且在数组上运行遍历时遇到了很多困难。

当我阅读这本书时,似乎我应该能够简单地在 Monad 之间遍历,但我无法用fp-ts来理解这个概念。

有人可以使用或任何其他方式解释以下内容array.traverse/sequence吗?

  1. 我怎样才能从TaskEither<Error, string[]>TaskEither<Error, Either<Error, string>[]>; 还是有更好的方法可以从单个错误变为嵌套错误,同时保持打字简单?
  2. 我怎样才能从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
)
4

1 回答 1

5

严格来说,Applicative就足够了traverse——你不需要一个 monad。

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


让我们看一些程序并想象一下,它们都使用带有TaskEither.

方案 3:(input: string) => TE.TaskEither<Error, string[]>

▶ 要么完全失败,Error要么成功string[]获取数据

程序 4:(input: string) => TE.TaskEither<Error, E.Either<Error, string[]>>

fetch结果Error或成功。如果成功,则进一步处理 Web 数据 - 导致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)))
        )
      )
    )
  );

代码沙盒

于 2020-04-10T17:20:41.220 回答