Contextbound "Temporal" causes: "Cannot resolve symbol flatMap"

114 Views Asked by At

I have something like

def test[F[_]: Sync: Console](counter: Int): F[Unit] =
  for {
    _ <- if(counter % 10000 == 0) Console[F].println(s"counter: ${counter}") else Sync[F].unit
    _ <- test(  counter + 1 )
  } yield ()

and want to add

_ <-   Temporal[F].sleep(50.milliseconds) 

in the for-statements. But adding the (then neccessary) context bound : Temporal causes the compile-error Cannot resolve symbol flatMap. What is wrong with this code?

I have tried the additional parameter

(implicit T: Temporal[F])

instead of : Temporal , but get the same error.

2

There are 2 best solutions below

0
Dmytro Mitin On

Both Sync and Temporal are Monad/FlatMap and this implicit ambiguity confuses how to desugar for-comprehension into a chain of .flatMap/.map.

Since Sync is now used only for .unit and Temporal already has monadic .unit, one option is to remove the context bound : Sync

import cats.effect.Temporal
import cats.effect.std.Console
import cats.syntax.flatMap._
import cats.syntax.functor._
import scala.concurrent.duration._

def test[F[_]: Console : Temporal](counter: Int): F[Unit] =
  for {
    _ <- if (counter % 10000 == 0) Console[F].println(s"counter: ${counter}")
         else Temporal[F].unit
    _ <- test(counter + 1)
    _ <- Temporal[F].sleep(50.milliseconds)
  } yield ()

Another option is to desugar the for-comprehension manually and specify explicitly which Monad instance out of Sync[F], Temporal[F] is used in .flatMap

import cats.effect.{Sync, Temporal}
import cats.effect.std.Console
import scala.concurrent.duration._

def test[F[_]: Sync : Console : Temporal](counter: Int): F[Unit] = {
   val x: F[Unit] =
     if (counter % 10000 == 0) Console[F].println(s"counter: ${counter}")
     else Sync[F]/*Temporal[F]*/.unit

   val y: F[Unit] = Sync[F]/*Temporal[F]*/.flatMap(x)(_ => test(counter + 1))

   Sync[F]/*Temporal[F]*/.flatMap(y)(_ => Temporal[F].sleep(50.milliseconds))
}
0
DenisNovac On

You might also pass temporal explicitly if you don't use it too much (like in fs2 kafka lib you only need it for commiting the offset):

class MyClass[F[_]: Sync: Logger](temporal: Temporal[F]) {

  for {
   _ <- f1
   _ <- f2
   _ <- f3(temporal)
  } yield ()

}


// creation of class at the IOApp example:

new MyClass[IO](implicitly[Temporal[IO]])