1

我有以下接口:

interface UserRepository {
  fun role(codename: String): IO<Option<Role>>

  fun accessRights(roleId: Long): IO<List<AccessRight>>
}

现在尝试使用它来组成这样的有效操作:

private fun retrieveRole(roleCodename: String): IO<Option<RoleTo>> =
  IO.fx {
    val role = userRepository.role(roleCodename).bind()
    role.map { r ->
      val ar = userRepository.accessRights(r.id).bind()
      RoleTo.of(r, ar)
    }
  }

代码无法在第二次绑定上编译(调用userRepository.accessRights(r.id).bind()sincebind是挂起函数。我如何正确组合两个操作?我不明白为什么第一次绑定有效但第二次没有,我不想让我的函数暂停还是我必须这样做?

4

2 回答 2

2

这是一个常见的问题。如果你有Option<A>或者Either<E, A>你想对它采取行动,你的第一反应是在块上使用它:

either.map { !someIO }

问题是未涵盖 left/none 选项。您应该在双方都采取行动,并在执行之前提取 IO。

!either.fold({ ioLogError(it) }, { someIo })

目前,从 0.10 开始,因为fold是一个内联函数,您也可以!在其中使用。我不能保证将来会是这样,因为这是我们为了方便而留下的一种意外的内联行为。

于 2019-09-21T22:16:00.290 回答
1

我能够使用以下traverse应用实例解决问题IO

private fun retrieveRole(roleCodename: String): IO<Option<RoleTo>> =
  IO.fx {
    val role = userRepository.role(roleCodename).bind()
    val accessRights = role.traverse(IO.applicative()) {
      userRepository.accessRights(it.id)
    }.bind()
    role.map2(accessRights) {
      (r, ar) -> RoleTo.of(r, ar)
    }
  }

感谢您指出map期望纯函数的事实。

于 2019-09-22T07:55:03.990 回答