【问题标题】:FP-TS Branching (Railway Oriented Programming)FP-TS 分支(面向铁路的编程)
【发布时间】:2021-12-03 08:18:21
【问题描述】:

我在尝试使用 FP-TS 实现事物时经常遇到的一种模式是,当我的管道涉及将 TaskEither 的分支分支和合并在一起时。

合并似乎工作得很好,因为我可以使用 sequenceT 创建数组并将它们传递到函数中,然后使用所有这些值。

似乎不太好用的是更复杂的依赖图,其中一个函数需要较早的项目,然后需要该函数的输出以及第一个任务的原始结果。

基本上是这样的函数签名(这可能不是 100% 正确的类型,但大致了解一下):

function fetchDataA(): TaskEither<Error, TypeA> {
}

function fetchBBasedOnOutputOfA(a: TypeA): TaskEither<Error, TypeB> {
}

function fetchCBasedOnOutputOfAandB(a: TypeA, b: TypeB): TaskEither<Error, TypeC> {
}

因为在管道中,你可以很好地为前两个作曲

pipe(
  fetchDataA(),
  TE.map(fetchBBasedOnOutputOfA)
)

而且这个管道按预期返回 TaskEither ,地图处理错误对我来说很好。

而要执行最后一个操作,我现在需要输入 TypeA 作为参数,但它不可用,因为它已传递给 B。

一种解决方案是让函数 B 同时输出 A 和 B,但这感觉不对,因为创建 B 的函数不应该知道某些其他函数也需要 A。

另一种方法是创建某种中间函数来存储 A 的值,但在我看来,这打破了使用 TaskEither 的全部意义,这是为了让我抽象出所有错误类型并自动处理。

我会有一些奇怪的功能:

async function buildC(a : TypeA): TaskEither<Error, TypeC> {
  const b = await fetchBBasedOnOutputOfA(a);
  // NOW DO MY OWN ERROR HANDLING HERE :(
  if (isRight(b)) {
    return fetchCBasedOnOutputOfAandB(a, b);
  }
  // etc.

那么有没有更惯用的方法来做到这一点,也许是创建树结构并遍历它们?虽然说实话,Traverse 的文档很少包含代码示例,而且我不知道如何使用它们。

【问题讨论】:

  • 附带说明,当您有多个彼此独立的计算时,通常会使用traversesequence 等函数。在您的情况下,您的每个函数都将依赖于先前的结果,这就是 chainDo 将派上用场的地方。
  • 我刚才问了一个类似的问题,得到了同样的答案:stackoverflow.com/questions/58560310/…

标签: typescript fp-ts


【解决方案1】:

我想说有两种惯用的写法:

  1. 使用对chain的嵌套调用:
pipe(
  fetchDataA(),
  TE.chain(a => { // capture `a` here
    return pipe(
      fetchBBasedOnOutputOfA(a), // use `a` to get `b`
      TE.chain(b => fetchCBasedOnOutputOfAandB(a, b)) // use `a` and `b` to get `c`
    )
  })
)
  1. 使用Do 表示法:fp-ts 公开了一种“do”语法,可以缓解chain 的过度嵌套,尤其是当您需要捕获许多稍后在程序流的不同部分中重用的值时。
pipe(
  // begin the `do` notation
  TE.Do,
  // bind the first result to a variable `a`
  TE.bind('a', fetchDataA),
  // use your `a` to get your second result, and bind that to the variable `b`
  TE.bind('b', ({ a }) => fetchBBasedOnOutputOfA(a)),
  // finally, use `a` and `b` to get your third result, and return it
  TE.chain(({ a, b }) => fetchCBasedOnOutputOfAandB(a, b))
);

您可以查看 Do notation here 的语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-08
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 2016-07-31
    • 2023-02-01
    • 2022-09-25
    相关资源
    最近更新 更多