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

时间:2018-05-30 18:46:36

标签: scala functional-programming typeclass scalaz scala-cats

我正在设计我的代数数据类型,并面临无法提供隐式类型类的问题。这就是我所拥有的:

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

为了能够在不进行强制转换的情况下返回Halt extends Stream[Nothing, Nothing],我将其设为协变但是我需要Monad[F]类型类,以便将其操作用于提供的上下文F[_]。在这种情况下会有什么解决方案?

1 个答案:

答案 0 :(得分:3)

只有当Monad contra -variant时才会编译。否则你有:

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]的子类型。

  

在这种情况下会有什么解决方案?

不要像这样定义run?一般来说,因为scalaz和猫决定使他们的类型不变,所以当你尝试在co / contravariant类型中使用它们时会遇到麻烦。