Kotlin-倍数IO的组成

问题描述

我是Kotlin的Arrow Framework的新手,我有两个问题:

假设吧

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()

编辑: 我看到this post有相同的问题。在提供的答案中,它表示问题是没有包含left / none选项。但它涵盖了所有内容,将map应用于None时,获得None

解决方法

随着即将推出的新0.11.0版本,最惯用的方法是使用Arrow Fx协程。

将示例重写为Arrow Fx协程将是:

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中提取值。

问题是左/无选项未涵盖。但是它涵盖了所有内容,将地图应用于“无”时,预期会获得“无”。

您没错,它已经被覆盖了,但是!是一个暂停函数,并且map当前未内联,因此不允许您在内部调用!。在0.11.0版本中,Arrow-Core中数据类型的运算符为inline,以改善对suspend函数的支持,这将解决Suspension functions can be called only within coroutine body错误。

在其他功能语言中,例如,经常使用Haskell monad变压器(OptionT),但在Kotlin中,使用suspend更好地适合了它,并且与包装monad变压器相比还具有很多性能优势。 / p>

如另一篇文章中所述,您也可以始终使用traversesequence来翻转两个容器。 Option<IO<User>> -> IO<Option<User>>