Reputation: 27375
I'm designing my algebraic data type and faced a problem of unabling to provide implicit typeclass. Here is what I have:
sealed abstract class Stream[+F[_], +T] {
def run()(implicit M: Monad[F]): F[Unit] = Stream.run(this)
}
object Stream{
final case object Halt extends Stream[Nothing, Nothing]
private def run[F[_], T](stream: Stream[F, T])(implicit M: Monad[F]): F[Unit] = stream match {
case Halt => M.pure()
}
}
I got the compile error
Error:(10, 22) covariant type F occurs in invariant position in type
Monad[F] of value M def run()(implicit M: Monad[F]): F[Unit] = M.pure()
I made it covariant in order to be able to return Halt extends Stream[Nothing, Nothing]
without casting but yet I need Monad[F]
typeclass in order to use its operation for a context F[_]
provided. What would be a solution in this case?
Upvotes: 1
Views: 122
Reputation: 170713
This would only compile if Monad
were contra-variant. Otherwise you have:
val stream: Stream[Nothing, Nothing] = Halt
val stream1: Stream[Maybe, Int] = stream // by covariance
val x = stream1.run()(implicitly[Monad[Maybe]])
but Halt.run
only accepts a Monad[Nothing]
, so Monad[Maybe]
must be a subtype of Monad[Nothing]
.
What would be a solution in this case?
Not to define run
like this? Generally, because scalaz and cats decided to make their typeclasses invariant, you'll run into trouble when trying to use them in co/contravariant types.
Upvotes: 3