我在我的Kotlin后端项目中使用Arrow。我有这样的存储库:
interface UserRepository {
fun user(username: String): Try<Option<User>>
}现在我想更进一步,通过返回Kind<F, Option<User>>从具体的Try类型中抽象出来。我可以用下面的代码来实现:
interface UserRepository<F> {
fun user(username: String): Kind<F, Option<User>>
}
class IdRepository : UserRepository<ForId> {
fun user(username: String): Kind<ForId<Option<User>>> =
if (username == "known") Id.just(Some(User()))
else Id.just(None)
}但现在我正在努力使用它。我不明白我们怎么能说userRepository中的F必须是Monad,这样它才能在monad理解块中使用。假设我有一些定义如下的类:
class UserService<F>(ME: MonadError<F, Throwable>, repo: UserRepository<F>)
: MonadError<F, Throwable> by ME {
fun someOperations(username: String) : Kind<F, User> = bindingCatch {
val (user) = repo.user(username)
user.fold({ /* create user */ }, { /* return user */ })
}
}编译器抱怨说它不能在repo.user行绑定user,因为它需要Kind<ForTry, ...>,但是repo.user返回Kind<F, ...>,这在这里是未知的。如何正确地从Try中实现抽象,以便可以使用Id实例实现存储库,以及如何在服务类中使用这样的存储库?
发布于 2019-09-21 09:19:52
在0.10.0中,你可以使用Fx类型的类来执行monad绑定。它的变体是可用的,如您的示例上的kdoc中所述,其中每个变体代表您想要的能力级别。实际上,由于特效只能完全封装在IO中,因此大多数应用程序都使用IO.fx。如果您正在处理副作用,那么您只能替换支持挂起的运行时,所以这基本上将您的运行时选项缩小到Async<F>实例,因为挂起意味着潜在的异步工作。即IO、Rx等。但也永远不要尝试...这些对于急切、无效的纯计算是很好的。
/**
* Fx allows you to run pure sequential code as if it was imperative.
*
* @see [arrow.typeclasses.suspended.monad.Fx] // Anything with flatMap
* @see [arrow.typeclasses.suspended.monaderror.Fx] //Try, Either etc stop here
* @see [arrow.fx.typeclasses.suspended.monaddefer.Fx] // IO
* @see [arrow.fx.typeclasses.suspended.concurrent.Fx] // IO
*/
class UserService<F>(ME: MonadError<F, Throwable>, repo: UserRepository<F>)
: MonadError<F, Throwable> by ME {
fun someOperations(username: String) : Kind<F, User> =
fx.monadThrow {
val user = !repo.user(username)
user.fold({ /* create user */ }, { /* return user */ })
}
}
}如果您想了解更详细的解释,请访问https://slack.kotlinlang.org #箭头频道,我们将很乐意提供帮助,并在Kotlin中讨论FP
干杯!
https://stackoverflow.com/questions/58036032
复制相似问题