如何将两个 kleisli 箭头(函数)f:A -> Promise B
和 g: B -> Promise C
组合成 h:A -> 使用 fp-ts promise C
?
我熟悉 Haskell,所以我会这样问:>=>=>
(fish operator)的等价物是什么?
最佳答案
promise 由 Task
表示或 TaskEither
fp-ts
中的单子(monad),这是异步计算。 TaskEither
另外对故障进行建模并且与 Task<Either<...>>
相同.
Kleisli 箭头可以通过 chain
组成monad 的操作和 flow
(管道运算符(operator))。结果类似于 >=>
的应用程序Haskell 中的运算符。
TaskEither
做一个例子:
const f = (a: A): Promise<B> => Promise.resolve(42);
const g = (b: B): Promise<C> => Promise.resolve(true);
转换函数返回 Promise
返回的人 TaskEither
使用 tryCatchK
1:
import * as TE from "fp-ts/lib/TaskEither";
const fK = TE.tryCatchK(f, identity); // (a: A) => TE.TaskEither<unknown, B>
const gK = TE.tryCatchK(g, identity); // (b: B) => TE.TaskEither<unknown, C>
组成两者:
const piped = flow(fK, TE.chain(gK)); // (a: A) => TE.TaskEither<unknown, C>
这是 Codesandbox 的复制粘贴 block :
// you could also write:
// import { taskEither as TE } from "fp-ts";
import * as TE from "fp-ts/lib/TaskEither";
// you could also write:
// import {pipeable as P} from "fp-ts"; P.pipe(...)
import { flow, identity, pipe } from "fp-ts/lib/function";
import * as T from "fp-ts/lib/Task";
type A = "A";
type B = "B";
type C = "C";
const f = (a: A): Promise<B> => Promise.resolve("B");
const g = (b: B): Promise<C> => Promise.resolve("C");
// Alternative to `identity`: use `toError` in fp-ts/lib/Either
const fK = TE.tryCatchK(f, identity);
const gK = TE.tryCatchK(g, identity);
const piped = flow(fK, TE.chain(gK));
const effect = pipe(
"A",
piped,
TE.fold(
(err) =>
T.fromIO(() => {
console.log(err);
}),
(c) =>
T.fromIO(() => {
console.log(c);
})
)
);
effect();
为什么没有 promise ?
JavaScript Promise 不遵守 monadic API ,例如它们是 eagerly computed 2。在函数式编程中,副作用会被尽可能地延迟,所以我们需要使用 Task
形式的兼容包装器。或 TaskEither
.
1 identity
只是在失败情况下转发错误。您也可以使用 toError
.
2 Incorporate monads and category theory #94如果您对历史原因感兴趣,值得一读。
关于 typescript :如何 kleisli compose (monadic compose) Promise monad using fp-ts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64514213/