问题描述
我是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>
如另一篇文章中所述,您也可以始终使用traverse
或sequence
来翻转两个容器。 Option<IO<User>> -> IO<Option<User>>