I'm using Arrow in my Kotlin backend project. I have repositories like this:
interface UserRepository {
fun user(username: String): Try<Option<User>>
}
Now I want to go step further and abstract from concrete Try
type with returning Kind<F, Option<User>>
instead. I was able to do it with this code:
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)
}
But now I'm struggling to use it. I don't understand how we can say that the F
in userRepository
has to be a Monad, so that it can be used in monad comprehension block. Suppose I have some class defined like this:
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 */ })
}
}
The compiler complains that it can't bind user
on line repo.user
as it requires the Kind<ForTry, ...>
but the repo.user
returns Kind<F, ...>
which is unknown here. How to properly achieve abstraction from Try
so that I can implement repositories with Id
instances and how to use such repositories in service classes?