【问题标题】:Managing array of monads in fp-ts and Functional Programming在 fp-ts 和函数式编程中管理单子数组
【发布时间】:2020-07-22 18:45:54
【问题描述】:

我是函数式编程的新手,在数组上运行遍历时遇到了很多困难。

当我阅读 this book 时,似乎我应该能够简单地在 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
)

【问题讨论】:

    标签: arrays typescript functional-programming monads fp-ts


    【解决方案1】:

    严格来说,Applicative 足以满足 traverse - 你不需要单子。

    TaskEither&lt;Error, string[]&gt;TaskEither&lt;Error, Either&lt;Error, string&gt;[]&gt;?

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

    TaskEither&lt;Error, Either&lt;Error, string[]&gt;&gt;TaskEither&lt;Error, Option&lt;string[]&gt;&gt;?

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

    具体选择的结构取决于您的环境和目的。 ▶Option:强调缺席/在场; ▶ Either:在Left 中允许更具体的错误类型。


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

    方案三:(input: string) =&gt; TE.TaskEither&lt;Error, string[]&gt;

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

    方案四:(input: string) =&gt; TE.TaskEither&lt;Error, E.Either&lt;Error, string[]&gt;&gt;

    fetch 产生 Error 或成功。如果成功,则进一步处理网络数据 - 产生Error string[]

    方案五:(input: string) =&gt; TE.TaskEither&lt;Error, E.Either&lt;Error, string&gt;[]&gt;

    ▶ 与程序 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

    【讨论】:

    • 非常感谢@ford04。您是否推荐任何资源来阅读有关这些概念的更多信息以掌握它们?当我看到代码时,我想我明白了,但我很难自己到达那里。
    • 尤其对于fp-ts,我发现作者Giulio Canti的Getting started系列和其他文章对于更深入的理解非常有用。除此之外,只需尝试您获得的代码示例:-)。不幸的是,fp-ts(还)在 TS 操场上不起作用,所以我用在这里链接一个沙箱。您还可以在 JS + 其他语言中找到非常好的文章,了解更一般的 fp 概念,因此可能值得为它开放。
    猜你喜欢
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多