#scala #scala-cats #for-comprehension #reader-monad
#scala #scala-cats #для-понимания #читатель-монада #считыватель-монада
Вопрос:
import cats.data.ReaderT
import cats.instances.either._
trait Service1
trait Service2
case class Cats(name:String)
type FailFast[A] = Either[List[String], A]
type Env = (Service1, Service2, Cats)
type ReaderEnvFF[A] = ReaderT[FailFast, Env, A]
def toReaderEnvFF[A](input:A):ReaderEnvFF[A] =
ReaderT((_:Env) => Right(input))
def c:ReaderEnvFF[Cats] =
for {
cats <- toReaderEnvFF((_:Env)._3)
} yield cats // This line is 26
Ошибка:
Ошибка: (26, 11) несоответствие типов; найдено: T1.this.Env => com.savdev.Cats (который расширяется до) ((com.savdev.Service1, com.savdev.Service2, com.savdev.Cats)) => com.savdev.Требуются кошки: com.savdev.Кошки } дают кошек
Не могли бы вы объяснить, почему cats не является com.savdev.Cats
? И почему в ошибке говорится, что она расширена до функции с методом возврата [Cats]
, бот не FailFast[Cats]
Я пытаюсь применить точно такую же логику, как здесь:
trait Service1 { def s1f = Option(10) }
trait Service2 {
type ReaderS1[A] = ReaderT[Option,Service1,A]
import cats.syntax.applicative._
import cats.instances.option._
def s2f:ReaderS1[Int] =
for {
r2 <- ReaderT((_: Service1).s1f)
r1 <- 1.pure[ReaderS1]
} yield r1 r2
}
В этом примере я мог бы преобразовать функцию Service1.s1f в ее результат r2, и он отлично работает. Почему я не могу, например, написать что-то вроде:
for {
cats <- ReaderT((_:Env)._3)
...
Ответ №1:
toReaderEnvFF((_: Env)._3)
на самом деле cats <- toReaderEnvFF((_: Env)._3)
это toReaderEnvFF[A]((_: Env)._3)
для некоторого типа A
. Что A
сейчас? Поскольку (_: Env)._3
(он же input
в toReaderEnvFF
) имеет тип, Env => Cats
тогда тип A
является Env => Cats
. So toReaderEnvFF((_: Env)._3)
имеет тип ReaderEnvFF[Env => Cats]
, а cats
in cats <- toReaderEnvFF((_: Env)._3)
имеет тип Env => Cats
.
x <- SomeMonad[T]
Переменная x
In имеет тип T
(теперь SomeMonad
есть ReaderEnvFF
, T
is Env => Cats
).
ReaderT((_: Service1).s1f)
в вашем втором примере имеет тип, ReaderT[Option, Service1, Int]
поэтому r2
в r2 <- ReaderT((_: Service1).s1f)
имеет тип Int
. Но в вашем первом примере toReaderEnvFF((_: Env)._3)
имеет тип ReaderEnvFF[Env => Cats]
, иначе ReaderT[FailFast, Env, Env => Cats]
поэтому cats
в cats <- toReaderEnvFF((_: Env)._3)
имеет тип Env => Cats
. В этом разница.
Если вы хотите работать с ReaderEnvFF[Cats]
, вам следует измениться cats <- toReaderEnvFF(???)
. Например
def c:ReaderEnvFF[Cats] =
for {
cats <- toReaderEnvFF(Cats("aaa"))
} yield cats
Комментарии:
1. но могу ли я получить cats из depedency? Потому что Cats является частью Env
2. @Alexandr Откуда взялся? Если у вас есть
ReaderEnvFF[Env]
(например, сKleisli#tap
), вы можете получитьReaderEnvFF[Cats]
(сKleisli#map(..)
) .3. вы знаете, это все еще не ясно. В
r2 <- ReaderT((_: Service1).s1f)
типеr2
это Int, но в том же / подобном выражении:cats <- ReaderT((_:Env)._3)
cats имеет типEnv => Cats
. Для меня синтаксис тот же. Я все еще не вижу разницы. Атрибуты ReaderT не могут повлиять на это правильно? Не могли бы вы объяснить это другими словами.4. @Alexandr
(_: Service1).s1f
имеет типService1 => Option[Int]
, поэтомуReaderT((_: Service1).s1f)
имеет типReaderT[Option,Service1,Int]
, поэтомуr2
inr2 <- ReaderT((_: Service1).s1f)
имеет типInt
.(_:Env)._3
имеет типEnv => Cats
, поэтомуReaderT((_:Env)._3)
имеет типReaderT[Id,Env,Cats]
, поэтомуcats
incats <- ReaderT((_:Env)._3)
имеет типCats
.5. @Alexandr Дело не в синтаксисе, а в типах.