使用Arrow 1.2.0 parZipOrAccumulate绑定Nel<ApplicationError>编译失败求助
解决方案
核心问题分析
你的代码里的bind()编译失败,本质是错误类型不兼容:
getUser/getDepartment/save返回的是Either<ApplicationError, *>,单个错误类型- 外层
either块的错误通道是Nel<ApplicationError>(非空列表),bind()要求抛出的错误必须和通道类型匹配
修正后的代码
override suspend fun execute(param: AddUserToDepartmentInfo): Either<Nel<ApplicationError>, Department> = either { // 1. parZipOrAccumulate直接接收返回Either的挂起函数,无需内部bind val pair: Pair<User, Department> = parZipOrAccumulate( errorCombiner = { e1: ApplicationError, e2: ApplicationError -> nonEmptyListOf(e1, e2) }, fa = { getUser(param.userLegalId) }, fb = { getDepartment(param.departmentCode) } ) { a, b -> Pair(a, b) }.bind() // 2. 单个错误转Nel后再bind,匹配外层错误类型 saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode)) .leftMap { nonEmptyListOf(it) } .bind() pair.second }
关键修正点
- 移除parZipOrAccumulate内部的bind:
parZipOrAccumulate的设计就是接收两个返回Either<L, R>的挂起函数,自动并行执行并通过errorCombiner合并错误为Nel<ApplicationError>,内部不需要用bind提前抛出错误。 - 单个错误转Nel:对于
save这类返回单个错误的函数,用leftMap { nonEmptyListOf(it) }把ApplicationError包装成Nel<ApplicationError>,再调用bind()就符合外层either块的错误类型要求了。
额外优化(可选)
可以给Either<ApplicationError, *>加一个扩展函数,简化单个错误转Nel的操作:
fun <R> Either<ApplicationError, R>.toNelEither(): Either<Nel<ApplicationError>, R> = leftMap { nonEmptyListOf(it) }
之后save的调用可以简化为:
saveUserDrivenPort.save(...).toNelEither().bind()
内容的提问来源于stack exchange,提问作者codependent
相关产品推荐
相关产品推荐

