如何使用Arrow-Kt扁平化嵌套的Either monad?
如何在Arrow-Kt中扁平化嵌套的Either Monad
嘿,这种嵌套Either的问题我之前也碰到过!在Arrow-Kt(以前的Kategory)里处理API调用时,一不小心就会搞出Either<Failure, Either<Failure, Success>>这种嵌套结构,确实挺烦的。不过别担心,有几种简单的方式能把它扁平化,我给你详细说说。
方法1:从源头避免嵌套(最推荐)
其实很多时候嵌套是因为用错了操作符——如果你在链式调用API的时候用了map而不是flatMap,就会产生嵌套Either。
举个例子:假设你有两个返回Either的函数,一个获取用户,一个根据用户获取资料:
// 模拟API调用函数 fun fetchUser(): Either<ApiError, User> = ... fun fetchProfile(user: User): Either<ApiError, Profile> = ... // ❌ 错误用法:用map会产生嵌套Either val nestedEither = fetchUser().map { user -> fetchProfile(user) } // 类型:Either<ApiError, Either<ApiError, Profile>> // ✅ 正确用法:用flatMap直接得到扁平化的结果 val flatEither = fetchUser().flatMap { user -> fetchProfile(user) } // 类型:Either<ApiError, Profile>
flatMap会自动把内层的Either“展开”,直接合并成一层,从根源上避免嵌套。
方法2:扁平化已存在的嵌套Either
如果已经产生了嵌套的Either<E, Either<E, A>>,Arrow-Kt提供了现成的工具来处理:
方式A:使用内置的flatten扩展函数
Arrow-Kt的Either专门为同错误类型的嵌套结构提供了flatten方法,直接调用就能展开:
import arrow.core.Either import arrow.core.flatten // 假设已经有了一个嵌套的Either实例 val nestedEither: Either<ApiError, Either<ApiError, User>> = ... // 一键扁平化 val flatEither: Either<ApiError, User> = nestedEither.flatten()
注意:这个方法要求外层和内层的错误类型必须一致,也就是Either<E, Either<E, A>>才能用。
方式B:手动用flatMap实现
如果不想依赖内置扩展,也可以手动用flatMap快速实现扁平化,原理很简单——直接把内层Either作为flatMap的返回值:
val nestedEither: Either<ApiError, Either<ApiError, User>> = ... val flatEither = nestedEither.flatMap { it } // 效果和flatten完全一样,类型也是Either<ApiError, User>
额外处理:错误类型不一致的情况
如果你的嵌套Either错误类型不一样,比如Either<NetworkError, Either<ParseError, User>>,那首先建议把所有错误封装成一个密封类,统一类型后再扁平化:
// 定义统一的错误密封类 sealed class ApiFailure { data class NetworkErr(val msg: String) : ApiFailure() data class ParseErr(val msg: String) : ApiFailure() } // 先把外层和内层的错误都转换成统一类型 val nestedEither: Either<NetworkError, Either<ParseError, User>> = ... val unifiedNested = nestedEither .mapLeft { ApiFailure.NetworkErr(it.message) } .map { it.mapLeft { err -> ApiFailure.ParseErr(err.message) } } // 现在就可以正常扁平化了 val flatEither = unifiedNested.flatten() // 类型:Either<ApiFailure, User>
内容的提问来源于stack exchange,提问作者MaxG
相关产品推荐
相关产品推荐

