如何在同步上下文中的arrow-kt中使用IO合成

时间:2019-09-21 10:12:18

标签: kotlin arrow-kt

我有以下界面:

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()是暂停函数,因此调用bind的方法。如何正确地编写两个操作?我不明白为什么第一个绑定可以工作,而第二个绑定不能工作不是,我不想使我的函数挂起,还是无论如何都必须挂起它?

2 个答案:

答案 0 :(得分:2)

这是一个常见的陷阱。如果您有Option<A>Either<E, A>并希望对其执行操作,那么您的第一个直觉就是在块上使用它:

either.map { !someIO }

问题是左/无选项未涵盖。您应该同时采取行动,并在执行前先提取IO。

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

现在,从0.10开始,由于fold是一个内联函数,因此您也可以在其中使用!。我不能保证将来会如此,因为这是我们为方便起见而保留的内联的意外行为。

答案 1 :(得分:1)

我能够使用traverseIO的适用实例来解决问题:

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需要纯函数的事实。