3
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

Error:

Error:(26, 11) type mismatch; found : T1.this.Env => com.savdev.Cats (which expands to) ((com.savdev.Service1, com.savdev.Service2, com.savdev.Cats)) => com.savdev.Cats required: com.savdev.Cats } yield cats

Can you please explain, why cats is not com.savdev.Cats? And why in the error, it says that it is expanded to a function with return method [Cats], bot not FailFast[Cats]

I try to apply exactly the same logic as here:

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
}

In this example I could convert function Service1.s1f to its result r2 and it works fine. Why I cannot, for instance write something like:

for {
 cats <- ReaderT((_:Env)._3)
...
Alexandr
  • 9,213
  • 12
  • 62
  • 102

1 Answers1

6

toReaderEnvFF((_: Env)._3) in cats <- toReaderEnvFF((_: Env)._3) is actually toReaderEnvFF[A]((_: Env)._3) for some type A. What is A now? Since (_: Env)._3 (aka input in toReaderEnvFF) is of type Env => Cats then type A is Env => Cats. So toReaderEnvFF((_: Env)._3) is of type ReaderEnvFF[Env => Cats] and cats in cats <- toReaderEnvFF((_: Env)._3) is of type Env => Cats.

In x <- SomeMonad[T] variable x is of type T (now SomeMonad is ReaderEnvFF, T is Env => Cats).

ReaderT((_: Service1).s1f) in your second example is of type ReaderT[Option, Service1, Int] so r2 in r2 <- ReaderT((_: Service1).s1f) is of type Int. But in your first example toReaderEnvFF((_: Env)._3) is of type ReaderEnvFF[Env => Cats] aka ReaderT[FailFast, Env, Env => Cats] so cats in cats <- toReaderEnvFF((_: Env)._3) is of type Env => Cats. That's the difference.

If you want to work with ReaderEnvFF[Cats] then you should change cats <- toReaderEnvFF(???). For example

def c:ReaderEnvFF[Cats] =
  for {
    cats <- toReaderEnvFF(Cats("aaa"))
  } yield cats 
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • but can I get cats from a depedency? Cause Cats is part of Env – Alexandr Apr 08 '19 at 08:37
  • @Alexandr Get from where? If you have `ReaderEnvFF[Env]` (for example with `Kleisli#tap`) you can get `ReaderEnvFF[Cats]` (with `Kleisli#map(..)`) . – Dmytro Mitin Apr 08 '19 at 10:12
  • you know, it still not clear. In the `r2 <- ReaderT((_: Service1).s1f)` type of `r2` is Int, but in the same/similar expression: `cats <- ReaderT((_:Env)._3)` cats is of type `Env => Cats`. For me syntax is the same. I still cannot see a difference. Attributes of ReaderT cannot affect it right? Can you please explain this in another words. – Alexandr Apr 09 '19 at 05:46
  • @Alexandr `(_: Service1).s1f` is of type `Service1 => Option[Int]`, so `ReaderT((_: Service1).s1f)` is of type `ReaderT[Option,Service1,Int]`, so `r2` in `r2 <- ReaderT((_: Service1).s1f)` is of type `Int`. `(_:Env)._3` is of type `Env => Cats`, so `ReaderT((_:Env)._3)` is of type `ReaderT[Id,Env,Cats]`, so `cats` in `cats <- ReaderT((_:Env)._3)` is of type `Cats`. – Dmytro Mitin Apr 09 '19 at 16:18
  • @Alexandr It's not about syntax, it's about types. – Dmytro Mitin Apr 09 '19 at 16:23