1

我是 Kotlin 的 Arrow 框架的新手,我有几个问题:

让我们假设

fun getUser(id: Int): IO<Option<User>>
fun getCards(user: User): IO<List<Card>>


fun getUserAndCards(id: Int): IO<Option<Pair<User, List<Card>>>> = IO.fx {
    when (val user = !userRepository.get(id)) {
        is None -> None
        is Some -> {
            val cards = !cardRepository.get(user.t.id)
            Some(Pair(user.t, cards))
        }
    }
}

如何以“箭头时尚”的方式实现相同的功能?

我设法得到:

fun getUserAndCards(id: Int): IO<Option<Pair<User, List<Card>>>> = IO.fx {
    userRepository.get(id).bind().map { user ->
        val cards = cardRepository.get(user.id).bind()
        Pair(user, cards)
    }
}

但我Suspension functions can be called only within coroutine body在第二个中获得bind()

编辑:我看到这个帖子有同样的问题。在提供的答案中,它说问题是未涵盖 left/none 选项。但是它被覆盖了,当申请map到 a时None,它预计会获得None.

4

1 回答 1

2

随着新的 0.11.0 版本即将发布,最惯用的方法是使用 Arrow Fx Coroutines。

将示例重写为 Arrow Fx Coroutines 将是:

suspend fun getUser(id: Int): Option<User>
suspend fun getCards(user: User): List<Card>


suspend fun getUserAndCards(id: Int): Option<Pair<User, List<Card>>> =
  option {
    val user = !userRepository.get(id)
    val cards = !cardRepository.get(user.t.id)
    Pair(user.t, cards)
  }

您现在可以依靠option { }DSL 从Option.

问题是未涵盖 left/none 选项。但是它被覆盖了,当将 map 应用于 None 时,预计会获得 None。

你是对的,它被覆盖了,但它!是一个挂起函数,并且map当前没有内联,所以你不能在!里面调用。在该0.11.0版本中,来自 Arrow-Core 数据类型的运算符是inline,以改进对suspend函数的支持,这将解决Suspension functions can be called only within coroutine body错误。

OptionT在其他函数式语言中,例如 Haskell monad 转换器经常被使用suspend

正如在另一篇文章中提到的,您也可以随时使用traversesequence转动两个容器。Option<IO<User>> -> IO<Option<User>>

于 2020-08-16T07:14:35.127 回答