This perhaps been asked many times before, but none of the suggestions I've found help.
I have a simple Scala code that generates long number that depends on some side-effects. I'm wrapping thing in an IO monad, but according to the least power principle, I'm actually declaring my function as F[_]: Effect
. Now code won't compile and I don't understand why, please suggest what may be wrong
import cats.effect.{Clock, Effect}
import cats.syntax.all._
import java.util.concurrent.TimeUnit
...
def generateId[F[_]: Effect](rid: Long)(implicit F: Effect[F], clock: Clock[F]): F[Long] =
for {
currentTimeNanos <- clock.realTime(TimeUnit.NANOSECONDS)
tid <- F.delay(Thread.currentThread().getId)
} yield
(tid << 40 /* */ & 0xFFFFFF0000000000L) |
(rid << 16 /* */ & 0x000000FFFFFF0000L) |
(currentTimeNanos & 0x000000000000FFFFL)
[error] /.../package.scala:34:41: value flatMap is not a member of type parameter F[Long]
[error] currentTimeNanos <- clock.realTime(TimeUnit.NANOSECONDS)
[error] ^
[error] /.../package.scala:35:34: value map is not a member of type parameter F[Long]
[error] tid <- F.delay(Thread.currentThread().getId)
Also, if you have any suggestions on improving the code, let me know please.
The problem is that the context bound in F[_]: Effect
desugars into an implicit parameter, so the compiler is seeing something like this:
def generateId[F[_]](rid: Long)(implicit ev: Effect[F], F: Effect[F], ...): F[Long] = ...
That means that every time it tries to resolve an implicit Effect[F]
in the body of the method, it'll fail because it thinks the explicit F
and this synthetic ev
are ambiguous.
The solution is to drop either the context bound or the explicit implicit F: Effect[F]
parameter. I'd suggest killing the context bound, since the fact that Scala allows you to combine the two is part of the reason it's so easy to make this kind of error (and was in my view a serious misjudgement by the language designers, as I've said many times before).