Как абстрагироваться от Try in arrow-kt - PullRequest
0 голосов
/ 21 сентября 2019

Я использую Arrow в своем бэкэнд-проекте Kotlin.У меня есть такие репозитории:

interface UserRepository {
  fun user(username: String): Try<Option<User>>
}

Теперь я хочу пойти дальше и абстрагироваться от конкретного типа Try с возвратом Kind<F, Option<User>>.Я смог сделать это с помощью этого кода:

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

Но сейчас я изо всех сил пытаюсь его использовать.Я не понимаю, как мы можем сказать, что F в userRepository должна быть монадой, чтобы ее можно было использовать в блоке понимания монады.Предположим, у меня есть некоторый класс, определенный следующим образом:

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 */ })
  }
}

Компилятор жалуется, что он не может связать user в строке repo.user, так как для него требуется Kind<ForTry, ...>, но repo.user возвращает Kind<F, ...> что здесь неизвестноКак правильно добиться абстракции от Try, чтобы я мог реализовать репозитории с Id экземплярами и как использовать такие репозитории в классах обслуживания?

1 Ответ

1 голос
/ 21 сентября 2019

В 0.10.0 вы можете использовать класс типа Fx для выполнения монадного связывания.Его варианты доступны, как описано в KDOC над вашим примером, где каждый из них представляет уровень мощности, который вы хотите.На практике большинство приложений используют IO.fx, поскольку эффекты могут быть просто инкапсулированы в IO.Вы можете заменять среды выполнения только в том случае, если они поддерживают приостановку, если вы работаете с побочными эффектами, поэтому это в основном сужает параметры времени выполнения до экземпляров 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 #arrow channel, и мы будем рады помочь, потусоваться и обсудить FP в Kotlin

Приветствия!

...