How can we use context receivers and Arrow 1.2.0 parZipOrAccumulate? No required context receiver found: Cxt

huangapple go评论46阅读模式
英文:

How can we use context receivers and Arrow 1.2.0 parZipOrAccumulate? No required context receiver found: Cxt

问题

以下是代码的中文翻译部分:

给定以下函数

```kotlin
context(Raise<ApplicationError>)
suspend fun getUser(legalId: UserLegalId): User
context(Raise<ApplicationError>)
suspend fun getDepartment(departmentCode: DepartmentCode): Department
context(Raise<ApplicationError>)
suspend fun save(user: User): User

我想并行调用它们并累积它们的错误:

context(Raise<Nel<ApplicationError>>)
override suspend fun execute(param: AddUserToDepartmentInfo): Department {
    val pair: Pair<User, Department> =
        parZipOrAccumulate(
            { e1, e2 -> e1 + e2 },
            { getUser(param.userLegalId) },
            { getDepartment(param.departmentCode) }
        ) { a, b -> Pair(a, b) }
    saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
    return pair.second
}

然而,在parZipOrAccumulate内部的getUser()getDepartment()调用不会编译:

未找到所需的上下文接收器Cxt { context(arrow.core.raise.Raise<xxx.ApplicationError>) private open suspend fun getUser(...)}
英文:

Given the following functions:

context(Raise<ApplicationError>)
suspend fun getUser(legalId: UserLegalId): User
context(Raise<ApplicationError>)
suspend fun getDepartment(departmentCode: DepartmentCode): Department  
context(Raise<ApplicationError>)
suspend fun save(user: User): User

I want to invoke them in parallel and accumulate their errors:

        context(Raise<Nel<ApplicationError>>)
        override suspend fun execute(param: AddUserToDepartmentInfo): Department {
            val pair: Pair<User, Department> =
                parZipOrAccumulate(
                    {e1, e2 -> e1 + e2},
                    { getUser(param.userLegalId) },
                    { getDepartment(param.departmentCode) }
                ) { a, b -> Pair(a, b) }
            saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
            return pair.second
        }

However, the getUser() and getDepartment() invocations inside parZipOrAccumulate don't compile:

No required context receiver found: Cxt { context(arrow.core.raise.Raise<xxx.ApplicationError>) private open suspend fun getUser(...)

答案1

得分: 0

你可以尝试省略{e1, e2 -> e1 + e2}参数吗?在这种情况下不需要,因为外部Nel<ApplicationError>已经被推断出Nel累加器。

context(Raise<ApplicationError>)
suspend fun getUser(legalId: UserLegalId): User

context(Raise<ApplicationError>)
suspend fun getDepartment(departmentCode: DepartmentCode): Department

context(Raise<ApplicationError>)
suspend fun save(user: User): User

context(Raise<Nel<ApplicationError>>)
suspend fun execute(param: AddUserToDepartmentInfo): Department {
  val pair: Pair<User, Department> =
    parZipOrAccumulate(
      { getUser(param.userLegalId) },
      { getDepartment(param.departmentCode) }
    ) { a, b -> Pair(a, b) }
    
  // 将`Raise<ApplicationError>`转换为`ScopedRaiseAccumulate<ApplicationError>`
  recover({
    saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
  }) { raise(nonEmptyListOf(it)) }

  return pair.second
}
英文:

Can you try omitting the {e1, e2 -> e1 + e2} argument? That is not needed in this case because the Nel accumulator is inferred by the outer Nel<ApplicationError>.

context(Raise<ApplicationError>)
suspend fun getUser(legalId: UserLegalId): User

context(Raise<ApplicationError>)
suspend fun getDepartment(departmentCode: DepartmentCode): Department  

context(Raise<ApplicationError>)
suspend fun save(user: User): User

context(Raise<Nel<ApplicationError>>)
suspend fun execute(param: AddUserToDepartmentInfo): Department {
  val pair: Pair<User, Department> =
    parZipOrAccumulate(
      { getUser(param.userLegalId) },
      { getDepartment(param.departmentCode) }
    ) { a, b -> Pair(a, b) }
    
  // Turn `Raise<ApplicationError>` into `Raise<Nel<ApplicationError>>`
  recover({
    saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
  }) { raise(nonEmptyListOf(it)) }

  return pair.second
}

I tried this locally, and it works for me. The Raise<ApplicationError> is exposed as ScopedRaiseAccumulate<ApplicationError> in the lambda of parZipOrAccumulate.

huangapple
  • 本文由 发表于 2023年4月10日 21:54:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977728.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定