我在嘗試使用 FP-TS 實作事物時不斷遇到的一種模式是,當我有涉及分支和合并 TaskEither 分支的管道時。
合并似乎作業得很好,因為我可以使用 sequenceT 創建陣列并將它們通過管道傳輸到函式中,然后使用所有這些值。
似乎效果不佳的是更復雜的依賴圖,其中一個函式中需要較早的專案,然后需要該函式的輸出以及第一個任務的原始結果。
基本上像這樣的函式簽名(這可能不是 100% 正確的型別,但請了解它的要點):
function fetchDataA(): TaskEither<Error, TypeA> {
}
function fetchBBasedOnOutputOfA(a: TypeA): TaskEither<Error, TypeB> {
}
function fetchCBasedOnOutputOfAandB(a: TypeA, b: TypeB): TaskEither<Error, TypeC> {
}
因為在管道中,你可以很好地為前兩個組合
pipe(
fetchDataA(),
TE.map(fetchBBasedOnOutputOfA)
)
這個管道按預期回傳 TaskEither<Error, TypeB> ,地圖處理錯誤對我來說很好。
而要執行最后一個操作,我現在需要輸入 TypeA 作為引數,但它不可用,因為它已傳遞給 B。
一種解決方案是讓函式 B 同時輸出 A 和 B,但這感覺不對,因為創建 B 的函式不應該知道其他一些函式也需要 A。
另一種方法是創建某種中間函式來存盤 A 的值,但在我看來,這打破了使用 TaskEither 的全部意義,這是我抽象出所有錯誤型別并自動處理的。
我會有一些奇怪的功能:
async function buildC(a : TypeA): TaskEither<Error, TypeC> {
const b = await fetchBBasedOnOutputOfA(a);
// NOW DO MY OWN ERROR HANDLING HERE :(
if (isRight(b)) {
return fetchCBasedOnOutputOfAandB(a, b);
}
// etc.
那么有沒有更慣用的方法來做到這一點,也許創建樹結構并遍歷它們?盡管老實說,Traverse 的檔案很少包含代碼示例,我也不知道如何使用它們。
uj5u.com熱心網友回復:
我想說有兩種慣用的寫法:
- 使用嵌套呼叫
chain:
pipe(
fetchDataA(),
TE.chain(a => { // capture `a` here
return pipe(
fetchBBasedOnOutputOfA(a), // use `a` to get `b`
TE.chain(b => fetchCBasedOnOutputOfAandB(a, b)) // use `a` and `b` to get `c`
)
})
)
- 使用
Do符號:fp-ts公開了一種“do”語法,可以減輕與 的過度嵌套chain,特別是當您需要捕獲大量稍后在程式流的不同部分中重用的值時。
pipe(
// begin the `do` notation
TE.Do,
// bind the first result to a variable `a`
TE.bind('a', fetchDataA),
// use your `a` to get your second result, and bind that to the variable `b`
TE.bind('b', ({ a }) => fetchBBasedOnOutputOfA(a)),
// finally, use `a` and `b` to get your third result, and return it
TE.chain(({ a, b }) => fetchCBasedOnOutputOfAandB(a, b))
);
您可以在此處查看 Do 符號的語法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/317158.html
上一篇:打字稿推斷型別引數
