#scala #monad-transformers #scala-cats #reader-monad
#scala #монадные трансформеры #scala-кошки #читатель-монада
Вопрос:
Пример s3f1
и s3f2
функций, которые возвращают разные ReaderT:
type FailFast[A] = Either[List[String], A]
trait Service1 { def s1f:Option[Int] = Some(10) }
trait Service2 { def s2f:FailFast[Int] = Right(20) }
import cats.instances.option._
def s3f1: ReaderT[Option, Service1, Int] =
for {
r1 <- ReaderT((_: Service1).s1f)
} yield r1 1
import cats.syntax.applicative._
import cats.instances.either._
type ReaderService2FF[A] = ReaderT[FailFast, Service2, A]
def s3f2: ReaderService2FF[Int] =
for {
r1 <- ReaderT((_: Service2).s2f)
r2 <- 2.pure[ReaderService2FF]
} yield r1 r2
Я пытаюсь скомпоновать эти две функции, которые возвращают читателей с разными F[_]
контекстами и зависимостями: ReaderT[Option, Service1, Int]
и ReaderT[FailFast, Service2, Int]
Я должен как-то объединить F[_]
контекст, что означает объединить FailFast
с Option
. Я полагаю, имеет смысл объединить ее с FailFast[Option]
:
type Env = (Service1, Service2)
type FFOption[A] = FailFast[Option[A]]
type ReaderEnvFF[A] = ReaderT[FFOption, Env, A]
Как составить s3f1 и s3f2:
def c: ReaderEnvFF[Int] =
for {
r1 <- //s3f1
r2 <- //s3f2
} yield r1 r2
Комментарии:
1. Подходит ли вам мой ответ?
Ответ №1:
Поскольку вы пытаетесь составлять монады FailFast
и Option
в FFOption
, вам следует использовать еще один монадный преобразователь, так что FFOption[A]
должно быть OptionT[FailFast, A]
, а не просто FailFast[Option[A]]
.
import cats.instances.option._
import cats.instances.either._
import cats.syntax.applicative._
import cats.syntax.either._
import cats.syntax.option._
type Env = (Service1, Service2)
type FFOption[A] = OptionT[FailFast, A]
type ReaderEnvFF[A] = ReaderT[FFOption, Env, A]
def c: ReaderEnvFF[Int] =
for {
r1 <- ReaderT[FFOption, Env, Int](p => OptionT(Either.right(s3f1.run(p._1))))
r2 <- ReaderT[FFOption, Env, Int](p => OptionT(s3f2.run(p._2).map(_.some)))
} yield r1 r2
Это может быть переписано с помощью local
и mapF
:
def c: ReaderEnvFF[Int] =
for {
r1 <- s3f1.local[Env](_._1).mapF[FFOption, Int](opt => OptionT(opt.asRight))
r2 <- s3f2.local[Env](_._2).mapF[FFOption, Int](ff => OptionT(ff.map(_.some)))
} yield r1 r2