像 Cats Effect 中的 Chain Fibers在 fp-ts 生态系统中移植到 TypeScript

问题描述

我正在尝试将 Fiber 从 Scala/Catz 移植到 TypeScript/fp-ts,但遇到了关于如何链接/flatMap 的问题。

(编辑:最终我只是想创建一个可取消的异步 monad,对于 HTTP 请求将使用 axios,因为这些请求是可取消的。fp-ts 没有可取消的异步,只有不可取消的异步 TaskTaskEither。如果有比这更好的方法,我完全赞成。)

给出总体思路

type Monad<F,E,A> {
  chain: <B>(fab: (a:A) => F<E,B>) => (f: F<E,A>) => F<E,B>
}

Fiber

interface Fiber<E,A> {
  cancel: TaskEither<never,void> // TaskEither<A,B> is a typealias for () => Promise<Either<E,A>>
  join: TaskEither<E,A>
}

我如何实现 chain 以便

declare const chain: <B>(fab: (a:A) => Fiber<E,B>) => (f: Fiber<E,A>) => Fiber<E,B>

我的第一件事是:

const chain: <E,A,B>(fab: (a:A) => Fiber<E,A>):Fiber<E,B> = ({
  cancel: pipe(
    fiber.cancel,taskEitherChain(() => fiber.join),taskEitherChain(a => fab(a).cancel)),join: pipe(
    fiber.join,taskEitherChain(a => fab(a).join))
})

但这需要我运行 fiber.join链接到另一根光纤,以便我可以调用第二根光纤的 cancel。基本上,要取消第二根光纤,我必须先加入第一根。这给了我

的坏结果
declare fiberThatTakesTenSecondsToComplete: Fiber<string,number>
declare fiberFactory: (i:number) => Fiber<string,boolean>

await pipe(fiberThatTakesTenSecondsToComplete,chain(fiberFactory)).cancel()

最后一行需要 10 秒才能完成,因为 cancel 函数调用了第一个光纤的 .join

====

所有这一切的动机是,我为我的 API 使用包装在 TaskEither 类型中的 axios 调用,并且我想结合 axios 的内置功能,以一元方式取消 API 调用。寻找可取消的异步使我找到了 Catz Effect 的 Fiber,这就是我现在所处的位置。

能够取消它们也很有用,因为在 React 应用程序和 useEffect 中,最佳做法是返回一个函数,该函数将取消您在 useEffect调用的任何内容。所以像

const MyComponent = () => {
  useEffect(() => {
    apiFiberThatEventuallyDoesSomethingToTheUI.join()

    return apiFiberThatEventuallyDoesSomethingToTheUI.cancel
  },[])
}

如果组件在 API 调用仍然很热时卸载,您希望能够取消 API 调用,这样它就不会链接到使用 API 结果更新 UI 的代码部分。

我将 axios 调用与像这样的工厂绑定到 Fiber 中

const axiosGet = (...p: Parameters<typeof axios.get>) => {
  const cancelSource = axios.CancelToken.source()
  const { token: cancelToken } = cancelSource
  return {
    cancel: () => {
      return taskEitherRight(cancelSource.cancel()) // TaskEither<never,void>
    },join: tryCatch(() => axios.get(p[0],{ ...(p[1] ?? {}),cancelToken }),() => 'Error')
  }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)