如何实现支持短路求值的lazy altAll方法?
实现支持短路求值的lazyAltAll替代Option switch逻辑
你遇到的问题核心是alt.altAll会预先计算传入的整个Option数组,无法做到短路求值——也就是找到第一个Some值后就停止后续计算。下面是实现你想要的lazyAltAll的方案:
实现lazyAltAll函数
我们可以基于fp-ts的Alt类型,自己实现一个支持懒加载的版本,通过函数包裹每个Option生成逻辑,只有在需要的时候才执行:
import * as O from 'fp-ts/Option' import type { Alt } from 'fp-ts/Alt' const lazyAltAll = <A>(alt: Alt<O.Option>) => (initial: O.Option<A>) => (options: Array<() => O.Option<A>>): O.Option<A> => { return options.reduce((acc, getOption) => { // 如果已经找到Some值,直接短路返回 if (O.isSome(acc)) return acc // 否则执行当前函数生成Option,合并到累积值中 return alt.alt(acc)(getOption()) }, initial) }
使用示例
现在你可以按照预期的方式编写foo函数,所有Option生成逻辑都会延迟到需要时执行,且找到第一个Some后就停止后续计算:
function foo(a: number) { return lazyAltAll(O.Alt)<string>(O.none)([ () => O.fromPredicate(() => a >= 85)('A'), () => O.fromPredicate(() => a >= 75)('B'), () => O.fromPredicate(() => a >= 60)('C'), () => O.some('D'), ]) }
实现逻辑说明
- 用
reduce遍历选项数组,维护一个累积的Option值 - 每次迭代先检查累积值是否为
Some,如果是直接返回,实现短路 - 只有当累积值为
None时,才调用当前的函数生成新的Option,再通过alt.alt合并 - 这种方式避免了预先计算所有Option,完全符合你想要的短路求值逻辑
递归实现版本(可选)
如果你更喜欢递归风格的实现,也可以用下面的写法,逻辑更直观:
const lazyAltAllRecursive = <A>(alt: Alt<O.Option>) => (initial: O.Option<A>) => (options: Array<() => O.Option<A>>): O.Option<A> => { if (options.length === 0) return initial const currentOption = options[0]() return O.isSome(currentOption) ? currentOption : lazyAltAllRecursive(alt)(initial)(options.slice(1)) }
内容的提问来源于stack exchange,提问作者Mxcpanel
相关产品推荐
相关产品推荐

