1

I have a toy DSL

case class Logging[A](msg: String, action: A)
case class Persist[A](msg: String, action: A)
type Effect[A] = EitherK[Logging, Persist, A]

that I want to pair with an equally toy interpreter

case class CoLogging[A](run: String => A)
case class CoPersist[A](run: String => A)
type Interp[A] = Tuple2K[CoLogging, CoPersist, A]

Here is an program example:

def prog(implicit L: Logs[Effect], P: Persists[Effect]): Free[Effect, Unit] =
  P.store("bar") >> L.log("foo")

and here is the interpreter:

def interpretEffect(implicit CL: CoLogs[IO], CP: CoPersists[IO]): Cofree[Interp, IO[Unit]] = 
  Cofree.unfold(IO.pure(())) { a: IO[Unit] => Tuple2K(CoLogging(CL.coLog(a)), CoPersist(CP.coPersist(a))) }

I've paid due diligence and defined functors as well as injection implicits. The compiler complains that it cannot find an instance cats.Functor[[A]cats.data.Tuple2K[example.CoLogging,example.CoPersist,A]], even though I am importing cats.data.Tuple2K._ where the instance is implicitly defined.

I can't see what I'm doing wrong, it must be something stupid. Do you have any idea? All the code can be seen in this gist.

Regis Kuckaertz
  • 991
  • 5
  • 14

2 Answers2

1

The compiler complains that it cannot find an instance cats.Functor[[A]cats.data.Tuple2K[example.CoLogging,example.CoPersist,A]], even though I am importing cats.data.Tuple2K._ where the instance is implicitly defined.

Functor[Tuple2K[F, G, ?]] is defined via Tuple2KInstances8#catsDataFunctorForTuple2K if Functor[F] and Functor[G] were defined. The thing is that Functor[CoLogging] and Functor[CoPersist] weren't.

Add

object CoLogging {
  implicit val coLoggingFunctor: Functor[CoLogging] = new Functor[CoLogging] {
    override def map[A, B](fa: CoLogging[A])(f: A => B): CoLogging[B] = CoLogging(fa.run andThen f)
  }
}

and

object CoPersist {
  implicit val coPersistFunctor: Functor[CoPersist] = new Functor[CoPersist] {
    override def map[A, B](fa: CoPersist[A])(f: A => B): CoPersist[B] = CoPersist(fa.run andThen f)
  }
}

and everything should compile.

The thing is the order of implicits. Move object functors to the beginning and everything should compile.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • 1
    I knew this, but they _are_ defined [here](https://gist.github.com/regiskuckaertz/334fa76da70dbd4b7d13a58e9d3ee24e#file-cofree-scala-L67-L73) – Regis Kuckaertz May 17 '18 at 11:29
  • @RegisKuckaertz OK, then the thing is the order of implicits. Move object `functors` to the beginning and everything should compile. – Dmytro Mitin May 17 '18 at 11:32
  • what the...?? it worked. This is complete nonsense. this language is so weak. thanks for the tip! – Regis Kuckaertz May 17 '18 at 19:06
0

For using cats functors in your code, you need to try to add settings in your build.sbt file.

scalacOptions += "-Ypartial-unification"

Maybe ths will hepls you. This is limitation of scala compiler https://issues.scala-lang.org/browse/SI-2712

Harmeet Singh Taara
  • 6,483
  • 20
  • 73
  • 126