何时选用E.altW而非E.orElse?二者差异及适用场景解析
fp-ts中E.altW与E.orElse的区别及适用场景
你在例子中用E.altW和E.orElse实现了功能完全一致的解析器Semigroup,这是因为当前场景没有用到二者的核心差异。下面从类型签名和适用场景两方面拆解区别:
核心差异:类型与参数能力
1. altW(含非宽版alt)
- 类型签名简化版:
Either<E, A> => (() => Either<E, A | B>) => Either<E, A | B> - 核心特点:
- 备选函数不接收原错误值,仅返回一个新的
Either - 要求左右两边的错误类型必须一致(
altW通过类型宽化允许成功类型兼容,比如你例子中string和number合并为string | number) - 语义更偏向“备选分支”:如果当前Either失败,就用另一个备选的Either
- 备选函数不接收原错误值,仅返回一个新的
2. orElse
- 类型签名简化版:
Either<E, A> => ((e: E) => Either<E2, A>) => Either<E2, A> - 核心特点:
- 备选函数接收原错误值作为参数,可以基于错误信息做逻辑判断
- 允许修改错误类型(从
E变为E2),成功类型保持一致 - 语义更偏向“错误处理分支”:针对当前Either的错误,做自定义处理后返回新的Either
适用场景选择
优先用alt/altW的场景
当你只需要“当前失败就试另一个备选”,不需要关心失败原因,也不需要修改错误类型时,alt/altW是更贴合语义的选择,比如你例子中的解析器拼接:
// 语义清晰:解析a失败,就试解析b pipe( a(input), E.altW(() => b(input)) );
必须用orElse的场景
当你需要基于原错误做处理时,orElse是唯一选择,比如:
- 根据错误类型返回不同的 fallback 数据
- 把底层错误包装成上层业务错误
- 错误日志上报后返回默认值
示例代码:
pipe( fetchUserInfo(userId), // Either<NetworkError, UserInfo> E.orElse((err) => { // 基于原错误类型做处理 if (err.code === 'TIMEOUT') { console.warn('请求超时,使用缓存数据'); return E.right(getCachedUserInfo(userId)); // Either<never, UserInfo> } else { // 包装错误类型 return E.left(new UserFetchError('获取用户信息失败', err)); // Either<UserFetchError, UserInfo> } }) );
内容的提问来源于stack exchange,提问作者Danielo515
相关产品推荐
相关产品推荐

