当类型是协变时,为什么我们不能提供隐式类型类?

Why can't we provide implicit typeclass when a type is covariant?

我在设计我的代数数据类型时遇到了无法提供隐式类型类的问题。这是我拥有的:

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()
  }
}

我遇到了编译错误

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()

我让它协变是为了能够 return Halt extends Stream[Nothing, Nothing] 无需强制转换,但我需要 Monad[F] 类型类以便将其操作用于上下文 F[_] 假如。在这种情况下有什么解决方案?

只有当 Monadcontra 变体时才会编译。否则你有:

val stream: Stream[Nothing, Nothing] = Halt
val stream1: Stream[Maybe, Int] = stream // by covariance
val x = stream1.run()(implicitly[Monad[Maybe]])

但是Halt.run只接受Monad[Nothing],所以Monad[Maybe]必须是Monad[Nothing]的子类型。

What would be a solution in this case?

不是这样定义run?通常,因为 scalaz 和 cats 决定使它们的类型类不变,所以当您尝试在 co/contravariant 类型中使用它们时,您会 运行 遇到麻烦。