fp-ts新手求助:如何根据条件切换TaskEither并优化组合逻辑
嘿,作为fp-ts新手,能写出这样的链式调用已经很棒啦!针对你这个根据第一个fetch结果决定是否发起第二个请求的场景,确实有几个可以优化的方向,让代码更简洁、更符合函数式编程的风格:
1. 提取重复的Fetch逻辑
你现在两次写了几乎完全一样的tryCatch(fetch...)代码块,把这段逻辑抽成一个单独的函数,既能减少重复,也方便后续维护:
import { pipe } from 'fp-ts/function'; import { TaskEither, tryCatch, chain, right } from 'fp-ts/TaskEither'; // 提取重复的fetch逻辑 const fetchExample = (): TaskEither<string, Response> => tryCatch( () => fetch('https://example.com'), reason => String(reason) ); pipe( fetchExample(), chain(d => d ? fetchExample() : right({})), // 后续处理逻辑 );
这样以后要修改请求URL或者错误处理方式,只需要改动这一个函数就行。
2. 用tap替代无意义的chain
你最后那个chain(finalResult => right(finalResult))其实是个恒等操作,如果只是为了执行打印日志这类副作用,用tap会更合适——它专门用来执行副作用但不改变原有的值,代码意图更明确:
import { tap } from 'fp-ts/TaskEither'; pipe( fetchExample(), chain(d => d ? fetchExample() : right({})), tap(finalResult => { console.log(finalResult); return right(undefined); // tap需要返回TaskEither,这里返回空的Right不影响原结果 }) );
如果使用fp-ts/function里的tap,写法还能更简洁:
import { tap } from 'fp-ts/function'; pipe( fetchExample(), chain(d => d ? fetchExample() : right({})), tap(finalResult => console.log(finalResult)) );
3. 让条件判断更清晰(可选)
如果你的判断逻辑比较复杂,或者想让代码意图更直观,可以用fromPredicate来封装判断逻辑,把“是否需要继续请求”的规则单独拎出来:
import { fromPredicate } from 'fp-ts/TaskEither'; // 定义判断规则:是否需要发起第二个请求 const shouldFetchAgain = (response: Response): boolean => Boolean(response); pipe( fetchExample(), // 先判断是否需要继续请求,不符合则直接返回默认值 chain(fromPredicate( shouldFetchAgain, () => right({}) // 不符合条件时返回的默认值 )), // 符合条件的话发起第二个请求,否则直接用之前的结果 chain(d => shouldFetchAgain(d) ? fetchExample() : right(d)), tap(finalResult => console.log(finalResult)) );
这个方式适合判断逻辑需要复用,或者想让链式调用的每一步职责更单一的场景。
总的来说,你的初始实现是完全可行的,这些优化都是为了让代码更易读、更易维护。如果你的判断逻辑很简单,保持三元表达式的写法也完全没问题——可读性永远是第一位的!
内容的提问来源于stack exchange,提问作者Dmytro Filipenko
相关产品推荐
相关产品推荐

