打字稿:如何 kleisli compose (monadic compose) Promise monad using fp-ts
Typescript: How to kleisli compose (monadic compose) Promise monad using fp-ts
如何使用 fp-ts 将两个 kleisli 箭头(函数)f:A -> Promise B
和 g: B -> Promise C
组合成 h:A -> Promise C
?
我熟悉Haskell所以我会这样问:>=>
(鱼算子)相当于什么?
Promise 由 fp-ts
中的 Task
or TaskEither
个单子表示,它们是异步计算。 TaskEither
额外模拟故障并且与 Task<Either<...>>
相同。
Kleisli 箭头可以通过 Haskell 中的 chain
operation of monads and flow
(pipe operator). The result resembles the application of >=>
运算符组成。
让我们用 TaskEither
做一个例子:
const f = (a: A): Promise<B> => Promise.resolve(42);
const g = (b: B): Promise<C> => Promise.resolve(true);
使用 tryCatchK
1 将返回 Promise
的函数转换为返回 TaskEither
的函数:
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 的复制粘贴块:
// 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();
为什么没有承诺?
JavaScript 承诺不遵守 monadic API, for example they are eagerly computed 2。在函数式编程中,副作用会尽可能地延迟,因此我们需要使用 Task
或 TaskEither
.
形式的兼容包装器
1 identity
只是在失败的情况下转发错误。您也可以使用 toError
.
2 Incorporate monads and category theory #94值得一读,如果你对历史原因感兴趣。
如何使用 fp-ts 将两个 kleisli 箭头(函数)f:A -> Promise B
和 g: B -> Promise C
组合成 h:A -> Promise C
?
我熟悉Haskell所以我会这样问:>=>
(鱼算子)相当于什么?
Promise 由 fp-ts
中的 Task
or TaskEither
个单子表示,它们是异步计算。 TaskEither
额外模拟故障并且与 Task<Either<...>>
相同。
Kleisli 箭头可以通过 Haskell 中的 chain
operation of monads and flow
(pipe operator). The result resembles the application of >=>
运算符组成。
TaskEither
做一个例子:
const f = (a: A): Promise<B> => Promise.resolve(42);
const g = (b: B): Promise<C> => Promise.resolve(true);
使用 tryCatchK
1 将返回 Promise
的函数转换为返回 TaskEither
的函数:
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 的复制粘贴块:
// 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();
为什么没有承诺?
JavaScript 承诺不遵守 monadic API, for example they are eagerly computed 2。在函数式编程中,副作用会尽可能地延迟,因此我们需要使用 Task
或 TaskEither
.
1 identity
只是在失败的情况下转发错误。您也可以使用 toError
.
2 Incorporate monads and category theory #94值得一读,如果你对历史原因感兴趣。