[英]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.