[英]How to manage monads in FP and specially in fp-ts
我对函数式编程和特别是fp-ts
库很fp-ts
。
我的问题包括两部分:
Task
到IO
,反之亦然,我们如何管理这种情况,我们应该始终保持在一个类型上,还是应该随着链的继续而改变?例如,假设我们有几个函数,我们想将它们组合在一起,如下所示,我知道这个例子可能不太实用,但它可以达到目的。
declare function getRnd(min: number, max: number): IO<number>; // Returns a random number within the range
declare function getPage(pageNo: number): TaskEither<Error, string>; // Make an Http request
declare function getLinks(pageContent: string): Option<string[]>; // Returns some links
// Let's say we wanna get a random page number and then return the links on it
// How do we compose these functions?
const getPageLinks = pipe(
getRnd(2, 4),
IO.chain(getPage), // I'm pretty sure TS will yells at me here
TaskEither.chain(getLinks),
log, // ?
)
1.) 将 Monad 从一种类型转变为另一种类型,我们如何管理这一点,我们应该始终保持在一种类型上,还是应该随着链的继续而改变?
您想要某种(自然)转换从IO
切换到Task
/ TaskEither
。 反过来对我来说没有意义,因为异步效果无法转换为同步效果。
chain
将保留结构。 所以getPage
IO.chain(getPage)
中的IO.chain(getPage)
需要一个签名number -> IO<whatever>
。 您可以改为使用map
添加额外的嵌套层,例如:
pipe(getRnd(2, 4), IO.map(getPage)); // I.IO<TE.TaskEither<Error, string>>
一般来说,方法没有对错之分,只看目的。 请注意,嵌套的数据类型越多,处理内部值就越复杂。 具有代数结构的函数式编程的一部分是避免在源头进行不必要的嵌套。
在您的情况下,将所有内容合并到一个统一的TaskEither
中确实TaskEither
- 类型IO<TaskEither<...>>
与TaskEither<...>
相比,您不会有任何优势。
2.) 如何简单地让打字稿跟随这些从一种到另一种类型的变化?
您可以使用TaskEither.rightIO
将IO
转换为TaskEither
( CodeSandbox ):
import { taskEither as TE, io as I, option as O, pipeable as P, either as E } from "fp-ts";
declare function log<T>(t: T): I.IO<T>;
const getPageLinks = P.pipe(
getRnd(2, 4),
TE.rightIO,
TE.chain(getPage),
TE.map(getLinks),
TE.chain(v => TE.rightIO(log(v)))
); // TE.TaskEither<Error, O.Option<string[]>>
这个也有效,因为 TS 使用结构类型(但我会推荐前者):
const getPageLinks2 = P.pipe(
getRnd(2, 4),
I.chain(getPage), // this also works
I.map(v => v.then(vv => E.either.map(vv, getLinks))),
I.chain(log)
); // I.IO<Promise<E.Either<Error, O.Option<string[]>>>>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.