Скала-кошки: читатель-композиция - PullRequest
3 голосов
/ 08 апреля 2019
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.Cats требуется: 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 Ответ

6 голосов
/ 08 апреля 2019

toReaderEnvFF((_: Env)._3) в cats <- toReaderEnvFF((_: Env)._3) на самом деле toReaderEnvFF[A]((_: Env)._3) для некоторого типа A. Что такое A сейчас? Поскольку (_: Env)._3 (он же input in toReaderEnvFF) имеет тип Env => Cats, тогда тип A равен Env => Cats. Таким образом, toReaderEnvFF((_: Env)._3) имеет тип ReaderEnvFF[Env => Cats] и cats в cats <- toReaderEnvFF((_: Env)._3) имеет тип Env => Cats.

В x <- SomeMonad[T] переменная x имеет тип T (теперь SomeMonad - ReaderEnvFF, T - Env => Cats).

ReaderT((_: Service1).s1f) во втором примере имеет тип ReaderT[Option, Service1, Int], поэтому r2 в r2 <- ReaderT((_: Service1).s1f) имеет тип Int. Но в вашем первом примере toReaderEnvFF((_: Env)._3) имеет тип ReaderEnvFF[Env => Cats] aka 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 
...